Date Conversion and date difference issue in swift - ios

In one of my app I have date and time for multiple data fetching from server. I have shown this in tableview. Now from this I have to find some idle time for particular row by some condition by previous and next row's date and time difference. Something like departure and arrival of vehicle and idle time in between. I will show you the issued code where the issue occurs (only for I have both valid date).
let dFormater = NSDateFormatter()
dFormater.dateFormat = "ddMMMYYHHmm"
dFormater.locale = NSLocale(localeIdentifier: "en_US_POSIX")
dFormater.timeZone = NSTimeZone(name: "GMT")
dFormater.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601)
print(startDate)
print(endDate)
if let validFdate : NSDate = dFormater.dateFromString(startDate) {
if let validLdate : NSDate = dFormater.dateFromString(endDate) {
print(validFdate)
print(validLdate)
let minutes = validLdate.minutesFrom(validFdate)
print("LO P & N \(indexPath.row)= \(minutes)")
let hour = minutes/60
let min = minutes%60
let fullTime = NSString.init(format: "%02d:%02d", Int(hour),Int(min))
strToReturn = fullTime as String
}
}
And log for this is like
03JUN161411
04JUN160542
2015-12-20 08:41:00 +0000
2015-12-20 00:12:00 +0000
LO P & N 0= -509.0
04JUN160931
05JUN160506
2015-12-20 04:01:00 +0000
2015-12-19 23:36:00 +0000
LO P & N 0= -265.0
07JUN160530
07JUN162127
2015-12-20 00:00:00 +0000
2015-12-20 15:57:00 +0000
LO P & N 2= 957.0
08JUN160049
08JUN161616
2015-12-19 19:19:00 +0000
2015-12-20 10:46:00 +0000
LO P & N 1= 927.0
Now From this logged output, you can see that thought there is valid date in first two still it show wrong output as there are different date and in last two output there is perfect output as both date are of same date. And also why it changes date month and year. See
03JUN161411
2015-12-20 08:41:00 +0000
(I have asked another question only for date here)

Your date format is incorrect.
dFormater.dateFormat = "ddMMMYYHHmm"
Capital Y is the year in week-of-year based calendars. You need to use lower case Y:
dFormater.dateFormat = "ddMMMyyHHmm"

Related

Converting 12 digit ticks to Date

I am trying to convert 12 digit c# date time ticks formatted time. (648000000000). With the help of following link I added an extension to my code How to get 18-digit current timestamp in Swift?.
extension Date {
init(ticks: UInt64) {
self.init(timeIntervalSince1970: Double(ticks)/10_000_000 - 62_135_596_800)
}
}
let date = Date(ticks: 648000000000)
When I try to see result date it prints following;
0001-01-03 18:00:00 +0000
However, when I try to convert it hour and minute format output is irrelevant like 19:55
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
dateFormatter.string(from: date)
My first question is how can I format it to get only 18:00. Second is why it is printing 18:00 when I print only date, but 19:55 when I format it?
Just don't subtract 62_135_596_800
extension Date {
init(ticks: UInt64) {
self.init(timeIntervalSince1970: Double(ticks)/10_000_000)
}
}
1970-01-01 18:00:00 +0000
The other problem: When you create date and print it, the string is formatted in UTC time zone (offset GMT+0). But DateFormatter returns string representation dependent on its time zone, which is the local timezone by default.
You can fix your code just by setting dateFormatter's timeZone to UTC
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
18:00
Apparently your timestamp represents a duration as the number of 100-nanosecond ticks, not a date. If you divide the number by 10^7 then you get the number of seconds. These can be printed as a duration with a DateComponentsFormatter.
Example:
let ticks = 648000000000
let seconds = TimeInterval(ticks) / 10_000_000
let fmt = DateComponentsFormatter()
fmt.allowedUnits = [.hour, .minute]
print(fmt.string(from: seconds)!)
18:00
The duration is 64800 = 18 * 60 * 60 seconds, that are exactly 18 hours.

Calendar's startOfDay() gives incorrect time for some dates

I'm getting a date one hour out when calling startOfDay(for: ) with a parameter of Date(timeIntervalSince1970: 0)
For example:
let twoThousandAndOne = Date(timeIntervalSinceReferenceDate: 0)
let nineteenSeventy = Date(timeIntervalSince1970: 0)
print("Two thousand and one: \(twoThousandAndOne)")
print("Nineteen seventy: \(nineteenSeventy)")
let calendar = Calendar.current
print("Start of two thousand and one: \(calendar.startOfDay(for: twoThousandAndOne))")
print("Start of nineteen seventy: \(calendar.startOfDay(for: nineteenSeventy))")
Output:
Two thousand and one: 2001-01-01 00:00:00 +0000
Nineteen seventy: 1970-01-01 00:00:00 +0000
Start of two thousand and one: 2001-01-01 00:00:00 +0000
Start of nineteen seventy: 1969-12-31 23:00:00 +0000
Your timezone is UTC+1
Calendar considers the local timezone but print displays dates in UTC.
To print the dates created with Calendar in UTC add the UTC timezone
var calendar = Calendar.current
calendar.timeZone = TimeZone(secondsFromGMT: 0)!

Converting time from GMT in iOS behaving oddly (Reverse)

So I am trying to convert some times I receive in UTC/GMT to the local time zone using the following code:
let gmtFormatter: NSDateFormatter = NSDateFormatter()
gmtFormatter.timeZone = NSTimeZone(name: "GMT")
gmtFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let gmtDate: NSDate = gmtFormatter.dateFromString(dateString)!
print("GMT \(gmtDate)")
let localFormatter: NSDateFormatter = NSDateFormatter()
localFormatter.timeZone = NSTimeZone.localTimeZone()
localFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let localDate: NSDate = localFormatter.dateFromString(gmtFormatter.stringFromDate(gmtDate))!
print("Local \(localDate)")
However, I find that the conversion is working in revers. PST is UTC-8 and the outputs are 8 hours ahead instead of 8 hours behind. So I tested with a London Time Zone (CET) which is UTC+1 and should be 1 hour ahead of GMT. The results was a time that was 1 hour behind.
This was the string I am testing with: "2016-02-24 00:05:54"
For PST this should convert to 2016-02-23 04:05:54, but instead converts to 2016-02-24 08:05:54 (notice the way it should be is on the 23rd and not the 24th)
For CET this should convert to 2016-02-24 01:05:54, but instead converts to 2016-02-23 23:05:54 (notice the way it should be is on the 24th and not the 23rd)
Am I missing something glaring?
The problem is that in the second part of your code...
let localDate: NSDate =
localFormatter.dateFromString(gmtFormatter.stringFromDate(gmtDate))!
... you're doing the opposite of what you want. An NSDate is absolute. Its string representation is what is volatile, as it were. So having turned a string into a date with your first formatter, what you now want to do is turn that date into a string with your second formatter.
For example, I'm in California. Now, watch this:
let dateString = "2016-02-24 10:09:08"
let gmtFormatter: NSDateFormatter = NSDateFormatter()
gmtFormatter.timeZone = NSTimeZone(name: "GMT")
gmtFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let gmtDate: NSDate = gmtFormatter.dateFromString(dateString)!
print("GMT \(gmtDate)")
let localFormatter: NSDateFormatter = NSDateFormatter()
localFormatter.timeZone = NSTimeZone.localTimeZone()
localFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let localDateString = localFormatter.stringFromDate(gmtDate) // <-- !!!
print("Local \(localDateString)")
Result:
GMT 2016-02-24 10:09:08 +0000
Local 2016-02-24 02:09:08
That's correct. When it's 10 AM in London, it's 2 AM here.
To put it another way, if you think what you're doing is converting a date from one time zone to another, you have not understood what a date is. It is a date-time and a time zone. There is nothing to convert: it is completely determined, and it is correct no matter where you are, because it says what time zone it is.
Perhaps it would be a bit clearer to you if I changed the next-to-last line format to this:
localFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
The final output is then:
Local 2016-02-24 02:09:08 -0800
which is obviously correct.

NSDateFormatter decreases the day of date

I need to store Date variable in CoreData in iOS
I need to store the Date only without the Time, So I made a formatter that discard the time partition from the NSDate variable.
But I have a strange result:
This is my code:
let dateStr = "2016-02-14 11:27:01"
let df2 = NSDateFormatter()
df2.timeZone = NSTimeZone.defaultTimeZone()
df2.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(dateStr)
if let date = df2.dateFromString(dateStr) {
df2.dateFormat = "yyyy-MM-dd"
print("-> \(df2.dateFromString(df2.stringFromDate(date)))")
}
and this is the output:
2016-02-14 11:27:01
-> Optional(2016-02-13 20:00:00 +0000)
Why does the formatter decrease the day by one ?
I tried many dates with same issue
Your time zone is obviously UTC+4.
To get UTC set the time zone accordingly.
df2.timeZone = NSTimeZone(forSecondsFromGMT: 0)
But although you see a date 4 hours ago the NSDate object is treated correctly depending on your time zone. The print command displays always UTC ignoring the time zone information, because NSDate is just a wrapper for a Double number.

Swift Get previous years datetime at GMT+08:00 timezone

I need to get previous 5 years of GMT +08:00 timezone but I'm having trouble of getting the correct timezone.
let today = NSDate()
let gregorian = NSCalendar(calendarIdentifier: NSGregorianCalendar)
gregorian?.timeZone = NSTimeZone(forSecondsFromGMT: 60*60*8)
let offsetComponents = NSDateComponents()
offsetComponents.year = years
let nYearsDate: NSDate = gregorian!.dateByAddingComponents(offsetComponents, toDate: today, options: NSCalendarOptions(0))!
println("getNYearsDate: \(nYearsDate)")
I am getting 2010-07-23 11:44:47 +0000
instead of 2010-07-23 00:00:00 +0800
I need to get
2010-07-23 00:00:00 +0800 and 2010-07-23 23:59:59 +0800
is there anyway to achieve this in Swift and iOS 7.1 above?
You need to reset the time as well. Date periods are also best modeled with NSDateComponents.
// a little trick to get all calendar unit masks
let kAllCalendarUnits = NSCalendarUnit(rawValue: UInt.max)
// normalize the date
let components = NSCalendar.currentCalendar().components(
kAllCalendarUnits, fromDate: NSDate())
components.hour = 0
components.minute = 0
components.second = 0
let dateAtStartOfDay = NSCalendar.currentCalendar().dateFromComponents(components)!
// subtract 5 years
var period = NSDateComponents()
period.year = -5
let finalDate = NSCalendar.currentCalendar().dateByAddingComponents(period,
toDate: dateAtStartOfDay, options: [])!
Note that the method with date components will give you the correct day, regardless if the period contains one or two leap years.
The rest is just a question of how to display this date. This is done with NSDateFormatter. Eg.:
let formatter = NSDateFormatter()
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 60 * 60 * 8)
formatter.dateFormat = "yyyy-MM-dd hh:mm:ss Z"
formatter.stringFromDate(finalDate)
// "2010-07-23 6:00:00 +0800"
In case you are wondering why it says "6:00" instead of "8:00": I ran this code with my machine set to GMT+1, plus summer time +1. Obviously, to get "0:00" you have to subtract the desired time difference again, but that would be 8 hours earlier in the GMT time zone.

Resources