how to query by date offset in Parse with Swift? - ios

I want to set a constraint on a Parse query, that takes a birthday ( date), and only gathers results which are within 10 years.
So if the date is something like (1954-01-10 07:00:00 +0000)
then I want to get all records from 1944 to 1964.
Is there some way to do this using Parse query code?
Or,
do I have to obtain the date, then use swift code to offset it by 10 years, then write something like this
let currentUserBirthday = PFUser.currentUser()?.objectForKey("birthday")!
// set date 10 years greater and lower than currentUserBirthday
let datePlus10 = // add 10 years to date
let dateMinus10 = // subtract 10 years from date
dailyFourQuery?.whereKey("birthday", greaterThanOrEqualTo: datePlus10)
dailyFourQuery?.whereKey("birthday", lessThanOrEqualTo: dateMinus10)
edit: hey guys, i solved this by getting the age from the date, then adding or subtracting the integer offset from that number,
then using NSCalendar and creating components with modified values.
Thanks for all the help.
let currentUserBirthdayNSDate = currentUserBirthday as! NSDate
let dateComponents = calendar.components([NSCalendarUnit.Day, NSCalendarUnit.Month, NSCalendarUnit.Year, NSCalendarUnit.WeekOfYear, NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second, NSCalendarUnit.Nanosecond], fromDate: currentUserBirthdayNSDate)
let componentsPlus10 = NSDateComponents()
componentsPlus10.day = dateComponents.day
componentsPlus10.month = dateComponents.month
componentsPlus10.year = dateComponents.year + 10
componentsPlus10.hour = dateComponents.hour
componentsPlus10.minute = dateComponents.minute

You can refer to SwiftDate
// Reference date is: Thu, 19 Nov 2015 19:00:00 UTC (1447959600 from 1970)
let refDate = NSDate(timeIntervalSince1970: 1447959600)
// Remember: all parameters are optional; in this example we have ignored minutes and seconds
let newDate = refDate.add(years: 1, months: 2, days: 1, hours: 2)
// newdate is 2017-01-21 14:00:00 +0000
// This is equivalent to
let newDate2 = refDate + 1.years + 2.months + 1.days + 2.hours
do you want this?

Related

How to format a date range (with only one year string) in different locale's in iOS?

The date string in English: Jan 18 - Jan 26, 2018
Incorrect Korean date string: Jan 18 - 2018 Jan 26
What should happen in Korean: 2018 Jan 18 - Jan 26 (not exactly correct Korean, just referring to the location of the year. See accepted answer to see proper Korean date format)
Right now this requires to date formatters, but you have to hardcode which date formatter has the year, so the Korean date doesn't look right.
Is this possible to do in Swift/Objc without just putting the year string on both sides of the date range?
Use a DateIntervalFormatter:
let sd = Calendar.current.date(from: DateComponents(year: 2018, month: 1, day: 18))!
let ed = Calendar.current.date(from: DateComponents(year: 2018, month: 1, day: 26))!
let dif = DateIntervalFormatter()
dif.dateStyle = .medium
dif.timeStyle = .none
dif.locale = Locale(identifier: "en_US")
let resEN = dif.string(from: sd, to: ed)
dif.locale = Locale(identifier: "ko_KR")
let resKO = dif.string(from: sd, to: ed)
This results in:
Jan 18 – 26, 2018
2018. 1. 18. ~ 2018. 1. 26.
The output isn't exactly what you show in your question but the output is appropriate for the given locales.

Swift - Timezone off by one hour / secondsFromGMT incorrect

This should be a really simple question but I just can't seem to wrap my head around it.
Given my timezone is EDT (GMT-4), why does 04:00 in GMT turn into 23:00 and not 00:00?
// The offset is -4 hours
let offsetFromGMT = Calendar.current.timeZone.secondsFromGMT() / 60 / 60
// 2017-03-12 04:00
var destinationComponents = DateComponents()
destinationComponents.timeZone = TimeZone(secondsFromGMT: 0)
destinationComponents.year = 2017
destinationComponents.month = 03
destinationComponents.day = 12
destinationComponents.hour = -offsetFromGMT // 4 hours
// Why is this 2017-03-11 23:00 and not 2017-03-12 00:00?
let date = Calendar.current.date(from: destinationComponents)!
// Outputs 23
Calendar.current.dateComponents([.hour], from: date).hour
Calendar.current.timeZone.secondsFromGMT()
is the current GMT offset for your time zone. In your case that
is 4 hours, because the current time zone in New York is EDT = GMT-4,
with daylight saving time active.
So your destinationComponents and date are four o'clock in
the morning Greenwich time:
2017-03-12 04:00:00 +0000
At that point, the time zone in New York was EST = GMT-5, and
daylight saving time not active. Therefore that date is 2017-03-11 23:00 in your local time zone.
I would proceed differently, avoiding "secondsFromGMT".
Example: "2017-03-12 00:00:00" New York time is "2017-03-12 05:00:00" GMT.
var srcComponents = DateComponents()
srcComponents.timeZone = TimeZone(identifier: "America/New_York")!
srcComponents.year = 2017
srcComponents.month = 3
srcComponents.day = 12
srcComponents.hour = 0
srcComponents.minute = 0
let date = Calendar.current.date(from: srcComponents)!
print(date) // 2017-03-12 05:00:00 +0000

NSDateComponentsFormatter not supported large interval

let date = NSDate()
let future = NSDate.distantFuture()
let f = NSDateComponentsFormatter()
f.unitsStyle = .Full
f.allowedUnits = [.Year, .Month, .Day]
f.stringFromTimeInterval(future.timeIntervalSinceDate(date))
Result is "-57 years, 0 months, 26 days" which is wrong.
I thought this might cause from overflow, so I try smaller number and found that this weird behavior start at 69 years interval
let date = NSDate()
let sixtyEightYears = NSCalendar.currentCalendar().dateByAddingUnit(.Year, value: 68, toDate: date, options: NSCalendarOptions())!
let sixtyNineYears = NSCalendar.currentCalendar().dateByAddingUnit(.Year, value: 69, toDate: date, options: NSCalendarOptions())!
let f = NSDateComponentsFormatter()
f.unitsStyle = .Full
f.allowedUnits = [.Year, .Month, .Day]
future.timeIntervalSinceDate(date)
sixtyEightYears.timeIntervalSinceDate(date) // 2145916800
sixtyNineYears.timeIntervalSinceDate(date) // 2177452800
f.stringFromTimeInterval(sixtyNineYears.timeIntervalSinceDate(date)) // "-67 years, 1 month, 6 days"
Is this the Apple bug, or I did something wrong?
The method timeIntervalSinceDate whose reference date is 1 January 1970 causes the problem.
1970 + 68 = 2038
From Wikipedia:
Year 2038 problem
The Year 2038 problem is an issue for computing and data storage
situations in which time values are stored or calculated as a signed
32-bit integer, and this number is interpreted as the number of
seconds since 00:00:00 UTC on 1 January 1970 ("the epoch"). Such
implementations cannot encode times after 03:14:07 UTC on 19 January
2038, a problem similar to but not entirely analogous to the "Y2K
problem" (also known as the "Millennium Bug"), in which 2-digit values
representing the number of years since 1900 could not encode the year
2000 or later. Most 32-bit Unix-like systems store and manipulate time
in this "Unix time" format, so the year 2038 problem is sometimes
referred to as the "Unix Millennium Bug" by association.
Full article : Year 2038 problem

How to get year month day from NSDate for the current timezone

I am current at timezone UTC-05:00. When I call the function NSDate(timeIntervalSince1970:0), it returns back "Dec 31, 1969, 7:00 PM"
let date = NSDate.init(timeIntervalSince1970: 0) // "Dec 31, 1969, 7:00 PM"
print(date) // "1970-01-01 00:00:00 +0000\n"
I read about this How to get NSDate day, month and year in integer format? But the problem is that with the following, I always get 1969-12-31 because of the 5 hour time difference.
let calendar = NSCalendar.currentCalendar()
calendar.getEra(&era, year:&year, month:&month, day:&day, fromDate: date)
year // 1969
month // 12
day // 31
var hour = 0, minute = 0, second = 0
calendar.getHour(&hour, minute: &minute, second: &second, nanosecond: nil, fromDate: date)
hour // 19
minute // 0
second // 0
Is there a way to get the current year, month, day values and etc. in the current timezone. What I am looking for here is:
year // 1970
month // 01
day // 01
The timeIntervalSince1970 initializer gives you (as documented) an NSDate which is some number of seconds since Jan 1 1970 at 00:00:00 in UTC, not in your local time zone. Those results you're getting are correct, because they're showing your local time zone's offset from that time. You're passing in 0, so you're getting Jan 1 1970 at 00:00:00 UTC, and then NSCalendar is giving you the equivalent date and time in your local time zone.
If you want to get Jan 1 1970 at 00:00:00 in your local time zone, you need to request that date specifically from NSCalendar:
let calendar = NSCalendar.currentCalendar()
calendar.timeZone = NSTimeZone.localTimeZone()
let date = calendar.dateWithEra(1, year: 1970, month: 1, day: 1, hour: 0, minute: 0, second: 0, nanosecond: 0)
calendar.getEra(&era, year:&year, month:&month, day:&day, fromDate: date!)
year // 1970
month // 1
day // 1
This is not a 0 offset for timeIntervalSince1970. If you check, you'll see that the result corresponds to your time zone's offset from UTC:
date?.timeIntervalSince1970 // 25200, for me
This will return the current date ex. 02/26/2016
// Format date so we may read it normally
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd/M/yyyy"
let currentDate = String(dateFormatter.stringFromDate(NSDate()))
Swift 3.0
NSDateFormatter > DateFormatter && NSDate > Date
let df = DateFormatter()
df.timeZone = .current
df.dateStyle = .medium
df.timeStyle = .short
df.dateFormat = "dd/M/yyyy"
let currentDate = df.string(from: Date())

Core Plot CPTAxisLabelingPolicyAutomatic Days only

I'm using CPTAxisLabelingPolicyAutomatic on my x-axis which for time-line for days of a year (e.g. 07 March 2015).
This is my reference date:
let components = NSDateComponents()
components.month = 10
components.day = 29
components.year = 1970
components.hour = 0
components.minute = 0
components.second = 0
referenceDate = NSCalendar.currentCalendar().dateFromComponents(components)!
and here is part of my x axis style
x.labelingPolicy = .Automatic
let oneDay:NSTimeInterval = 60 * 60 * 24
x.majorIntervalLength = oneDay
x.minorTicksPerInterval = 0
let formatter = NSDateFormatter()
formatter.dateStyle = .MediumStyle
formatter.timeStyle = .NoStyle
let timeFormatter = CPTTimeFormatter(dateFormatter: formatter)
timeFormatter.referenceDate = referenceDate
x.labelFormatter = timeFormatter
The problem is eventhough, the x values are NSDate at 00:00:00 of the days they do not stick to the gridline for that specific date:
but if I use .FixedInterval policy I get the correct behaviour but I loose the autmatic labeling on pinching.
How can I benefit from the two world?
The automatic labeling algorithm doesn't know about dates, so it won't split the axis into "nice" date intervals like days or weeks. Right now, the fixed interval labeling policy is the best solution. It is up to you to determine the proper interval based on the range being displayed. There is an open issue to add proper date support, but it's pretty low priority and I can't guarantee when it will be done.

Resources