Swift configuring timezone with identifier changes GMT value - swift

I have the following playground code:
let dateFormatter = ISO8601DateFormatter()
let zurichTimeZone = TimeZone(identifier: "Europe/Zurich")
dateFormatter.timeZone = zurichTimeZone
// dateFormatter.timeZone = .init(abbreviation: "GMT+1:00")
// prints timezone +1
print(dateFormatter.string(from: Date(timeIntervalSince1970: TimeInterval(100400))))
// prints timezone +2
print(dateFormatter.string(from: Date(timeIntervalSince1970: TimeInterval(1665957700))))
The first output is "1970-01-02T04:53:20+01:00" and the second output is "2022-10-17T00:01:40+02:00". Why does the GMT value change? If use "Europe/Kalingrad" as the identifier, I will get +3 from the first and +2 from the second print. The problem won't appear when I'm setting the timezone with "dateFormatter.timeZone = .init(abbreviation: "GMT+1:00")". I also can't find this behaviour when I'm using "Pacific/Guam".

The named TimeZones take daylight saving time (DST) into consideration, while the ones created by a GMT offset do not.
Zurich is GMT+1 in winter time, but GMT+2 in summer time.
The 2 dates you create are on different sides of the clock change, so 1 uses summer time, while the other uses winter time. This is where the 1h time difference using the 2 different timezones is coming from.

Related

DateFormatter returns previous day

I've looked around and people have had problems with different years, random and changing results, and nil dates, but nothing like what I have, so I am asking here. Note I am in Playground right now.
I am taking strings in the format of "yyyy-mm-dd" and converting them to a different date format. Here is the code:
let example = "2001-11-03"
let dateFormatterInput = ISO8601DateFormatter()
dateFormatterInput.formatOptions = [.withFullDate, .withDashSeparatorInDate]
let date = dateFormatterInput.date(from: example)
let dateFormatterOutput = DateFormatter()
dateFormatterOutput.dateFormat = "MMMM dd, yyyy"
let output = dateFormatterOutput.string(from: date!)
The sidebar in Playground shows that the first reference to the previous day's date happens on the let date line. Also, this behavior happens on every date I've tried. In this example, it returns "November 2, 2001." I've tried different months, days, and years (1900s and 2000s) and it gives me the same result every time.
What am I doing wrong?
The key thing here is that ISO8601DateFormatter by default thinks that the time zone of your date string is GMT:
ISO8601DateFormatter.timeZone:
The time zone used to create and parse date representations. When unspecified, GMT is used.
However, the timeZone of DateFormatter by default (and also the side bar of the playground) assumes your device's local time zone:
DateFormatter.timeZone
The time zone for the receiver. If unspecified, the system time zone is used.
If your system time zone has a negative UTC offset on the start of the day 2001-11-03 UTC, then when seen from your time zone, that moment is actually in the day 2001-11-02. Hence the output you see.
Assuming you don't care about the actual value of date, and just care about the final string output, you can just set the timeZone of DateFormatter to GMT:
dateFormatterOutput.timeZone = TimeZone(identifier: "GMT")
Side note: You should also set locale when using a fixed format to avoid localisation issues:
dateFormatterOutput.locale = Locale(identifier: "en_US_POSIX")
Or better, just use one of the built-in, locale sensitive formats instead:
dateFormatterOutput.dateStyle = .medium
dateFormatterOutput.timeStyle = .none

Swift UTC TimeZone is not UTC

I have a question about Swift type TimeZone.
I need to get a UTC0 time zone to format my Date object. I'm creating TimeZone object like this.
let utcTimeZone = TimeZone(abbreviation: "UTC")
But when created this object gives me GMT0 time zone. Is this possible to get UTC0 time zone in Swift? Also what is the difference between GMT (fixed) and GMT (GMT) offset 0 in playground?
Xcode 10.3 Playground
Technically, there are really subtle differences between UTC and GMT (GMT could mean UT1), but the designers of the API thought they are practically the same (which they are), so they made this true:
TimeZone(identifier: "UTC") == TimeZone(identifier: "GMT")
They both represent a timezone with a constant offset of 0.
If you just want to show the letters "UTC" in some output text, use a DateFormatter:
let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: "UTC")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss 'UTC'"
print(formatter.string(from: Date()))
Or better yet, use a ISO8601DateFormatter, which adds a Z to the end of the date to indicate that the date time is in UTC:
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(identifier: "UTC")
print(formatter.string(from: Date()))
Also what is the difference between GMT (fixed) and GMT (GMT) offset 0 in playground?
The former comes from the Swift TimeZone class, and the latter comes from the Objective-C NSTimeZone class. One is the bridged version of the other. From the docs of NSTimeZone,
use NSTimeZone when you need reference semantics or other Foundation-specific behavior.
I've been there, according to google
There is no time difference between Coordinated Universal Time and Greenwich Mean Time
In other words, GMT is (basically) UTC, so you already have it!
offset 0 is referring to the timezones offset from UTC/GMT, which is 0, and would be potentially something like 240 if you were in EST (depending on if it's in minutes, hours, milliseconds etc.).
fixed on your second line means it's GMT and the offset data is potentially immutable. I wouldn't know without the playground open but I'd try changing the timezone after instancing that and see how if the offset can be changed post assignment.
You can use this instead of UTC, in some device only setting UTC not working
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let date = dateFormatter.date(from: "2020-01-23T11:55:00.000Z")

Time zone in swift - NSDate

i'm using xCode 7.2.1 ad Swift2, writing fo iOS.
i did a function for converting a String to a NSDate and that's :
class func StringToDateWithHour(data : String) -> NSDate
{
let dateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone(abbreviation: "CET");
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
guard let date = dateFormatter.dateFromString(data) else{
return NSDate()
}
return date
}
I don't understand why i get back the UTC time, INSTEAD of CET time.
When i try to convert a string like : "2016-2-21 10:00:00" i get back
"2016-2-21 09:00:00" , one hour less.
Thank you.
You're saying that you want to convert 10 am CET to a NSDate.
That correctly outputs 9 am UTC time (UTC is one hour behind CET time).
NSDate objects don't depend on time zones, they're just data from a particular point in time.
NSDate objects encapsulate a single point in time, independent of any particular calendrical system or time zone. Date objects are immutable, representing an invariant time interval relative to an absolute reference date (00:00:00 UTC on 1 January 2001).

Swift get difference between two dates in GMT

I recently noticed strange behaviour trying to find the difference between two dates (in seconds).
I have a datestring that is in GMT time:
2016-01-07 01:09:47.289000
I want to find how many seconds since that time NOW.
But I notice that when I use NSDate() I get the time of my local time, not GMT time.
How would I go about doing this?
Use the NStimeZone class to set time zone
let date = NSDate()
var formatter = NSDateFormatter()
let gmt = NSTimeZone(abbreviation: "GMT")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
formatter.timeZone = gmt
formatter.stringFromDate(date)
To compare, convert the current date from NSDate to "GMT" and then calculate the time interval between the two.

NSDate set timezone in swift

how can i return a NSDate in a predefined time zone from a string
let responseString = "2015-8-17 GMT+05:30"
var dFormatter = NSDateFormatter()
dFormatter.dateFormat = "yyyy-M-dd ZZZZ"
var serverTime = dFormatter.dateFromString(responseString)
println("NSDate : \(serverTime!)")
the above code returns the time as
2015-08-16 18:30:00 +0000
The date format has to be assigned to the dateFormat property of the date formatter instead.
let date = NSDate.date()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let str = dateFormatter.stringFromDate(date)
println(str)
This prints the date using the default time zone on the device. Only if you want the output according to a different time zone then you would add for example
Swift 3.*
dateFormatter.timeZone = NSTimeZone(name: "UTC")
Swift 4.*
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
also refer link http://www.brianjcoleman.com/tutorial-nsdate-in-swift/
how can i return a NSDate in a predefined time zone?
You can't.
An instance of NSDate does not carry any information about timezone or calendar. It just simply identifies one point in universal time.
You can interpret this NSDate object in whatever calendar you want. Swift's string interpolation (the last line of your example code) uses an NSDateFormatter that uses UTC (that's the "+0000" in the output).
If you want the NSDate's value as a string in the current user's calendar you have to explicitly set up a date formatter for that.
Swift 4.0
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
If you always have the same time zone for the input string, you can create two date formatters to output the local time zone (or a specified one):
let timeFormatterGet = DateFormatter()
timeFormatterGet.dateFormat = "h:mm a"
timeFormatterGet.timeZone = TimeZone(abbreviation: "PST")
let timeFormatterPrint = DateFormatter()
timeFormatterPrint.dateFormat = "h:mm a"
// timeFormatterPrint.timeZone = TimeZone(abbreviation: "EST") // if you want to specify timezone for output, otherwise leave this line blank and it will default to devices timezone
if let date = timeFormatterGet.date(from: "3:30 PM") {
print(timeFormatterPrint.string(from: date)). // "6:30 PM" if device in EST
} else {
print("There was an error decoding the string")
}
The number 1 means 1 regardless of language. Yet in English it's spelled as one, in Spanish it's una, in Arabic it wahid, etc.
Similarly 123982373 seconds pass 1970 is going to reflect differently in different timezones or calendar formats, but's all still 123982373 seconds passed 1970
The difference between 3 seconds and 7 seconds is 4 seconds. That doesn't require a calendar. Neither you need a calendar/timezone to know the difference in time between these two Epoch times 1585420200 and 1584729000
Dates are just a timeInterval from January 1, 1970 (midnight UTC/GMT). Dates also happen to have a string representation.
Repeating Nikolia's answer, Swift's default string interpolation (2015-08-16 18:30:00 +0000) uses a DateFormatter that uses UTC (that's the "+0000" in the output).
Calendars with the use of timezones give us a contextual representation that is just easier to understand than trying to calculate the difference between two gigantic numbers.
Meaning a single date (think of a single timeInterval since 1970) will have a different string interpretations per calendar. On top of that a calendar will itself vary based on time zones
I highly recommend that you go and play around with this Epoch converter site and see how selecting a different timezone will cause the string representations for the same moment/date/timeInterval to change
I also recommend to see this answer. Mainly this part:
Timezone is just an amendment to the timestamp string, it's not considered by the date formatter.
To consider the time zone you have to set the timeZone of the formatter
dateFormatter.timeZone = TimeZone(secondsFromGMT: -14400)