Dateformatter Returns Unexpected Date for Timezone

DateFormatter returns unexpected date for Timezone

In

let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "HHmmss"
timeFormatter.timeZone = TimeZone(identifier: "UTC")
let time = timeFormatter.date(from: "131006")

only a time is provided, but no day/month/year. In this case the date formatter uses a default date of Jan 1, 2001, as you can verify with

print(time!) // 2000-01-01 13:10:06 +0000

Daylight saving time was not active on that day, therefore
your local time for that point in time is 14:10, not 15:10.

To solve the issue, you can either combine the date and time strings
sent from the server and parse that, or convert the date string
first and set it as default date when converting the time string:

timeFormatter.defaultDate = ...

DateFormatter gives weird timezone for very old dates

In the past, each local area kept their own local mean time by observing the times of sun sets and sun rises. This meant that the local time at each town/city not be a nice whole number offset from Greenwich, like +17 minutes for example. This wasn't that big of a problem until people invented trains, which had schedules. At around the 19th century, countries around the world standardised their local times, and that is why we have nice whole number offsets like +1 hour (most of the time).

So in the year 1000, your timezone, Europe/Brussels was really 17 minutes ahead of Greenwich as far as the history we know. This bit of history got recorded in the IANA tz database, which is what TimeZone queries. That is why you got +00:17.

Interestingly, when I ask the TimeZone how many seconds it is from GMT at around the 1000s, it says 0:

let date = Date(timeIntervalSinceNow: 86400 * 365 * -1000)
// this is 0
TimeZone(identifier: "Europe/Brussels")!.secondsFromGMT(for: date)

It might have rounded the actual number of seconds down. Java can tell you the actual answer though:

// prints +00:17:30
System.out.println(ZoneId.of("Europe/Brussels")
.getRules().getOffset(LocalDate.of(1000, 1, 1).atStartOfDay()));

DateFormatter is Giving a Day before date

You are mixing a Date - which is a point in time - with a formatted Date string, which is something you can see on a watch or on a calendar.
Date is always referencing UTC (f.k.a. Greenwich Mean Time), so the output of print(date) will not print a calendar date but the UTC date and time.
If you convert that date to a "calendar entry" (by specifing a time zone etc.), you then will get the value that is displayed on your local watch, when in UTC its midnight on the 8th of March, 2021.
If you are living west of Greenwich, this will be the day before, because you are still on the 7th of March, waiting for the new day to arrive.

Unexpected result after formating string to date

Set the locale and timezone to avoid invalid results. The return value of the extension should be Date? since the string may not be a valid date.
And since dateFormat is not optional, it should be a valid date format, see here for more details.

import UIKit

extension String {
func toDate(dateFormat: String, locale : Locale? = nil, timezone: TimeZone? = nil) -> Date? { //locale and timezone are optional with a default nil value
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = dateFormat
dateFormatter.locale = locale
dateFormatter.timeZone = timezone
return dateFormatter.date(from: self)
}
}

You can use it like so:

let string = "01/24/2018 09:59:24"
let myLocale = Locale(identifier: "en_US_POSIX")
let myTimeZone = TimeZone(abbreviation: "PCT")

print(string.toDate(dateFormat: "MM/dd/yyyy HH:mm:ss",
locale: myLocale,
timezone: myTimeZone))

String to date with UTC timezone

The Date object does not have any inherent locale / time zone. It just represents a moment in time. If you want to see that Date as a string in a specific locale/time zone you have to use a date formatter. Or there's descriptionWithLocale. If you use print it will print a debug description of the Date instance in UTC.



Related Topics



Leave a reply



Submit