Currently i have missing understand on summertime, below is my context:
start summer time: June/1/2014 0h
end summer time: November/29/2014 0h
assume at the time 23h59 of November/29/2014 after passing => 0h00 November/30/2014 => the summertime will be minus 1 (-1) => 23h00 of November/29/2014 => it still under summer time (June/1/2014 0h - November/29/2014 0h)
So is my calculation above correct ?
Your misunderstanding is ignoring the fact that the time zone is part of the timestamp, and is necessary to make a timestamp in local time unambiguous.
If summer time ends at 00:00 at the beginning of November 30th, then the series of timestamps is:
2014-11-29 23:59:58 XST
2014-11-29 23:59:59 XST
2014-11-29 23:00:00 XWT
2014-11-29 23:01:01 XWT
[...]
2014-11-29 23:59:59 XWT
2014-11:30 00:00:00 XWT
(where "XST" is the summer timezone and "XWT" is the winter timezone). "2014-11-29 23:00:00 XST" and "2014-11-29 23:00:00 XWT" are two different times, one hour apart.
If you are given a local time between 2014-11-29 23:00 and 2014-11-30 00:00 without an indicator of whether it's XST or XWT, then it's impossible to turn it into a unique timestamp.
Related
If I run this query on my database
SELECT EXTRACT('epoch' FROM age('2021-01-01'::date, '2019-12-01'::date))
The result is 34149600.
But then if I try with 2019-12-02 (one day more)
SELECT EXTRACT('epoch' FROM age('2021-01-01'::date, '2019-12-02'::date))
The result is exactly the same 34149600!
As if the seconds passed from 02 december 2019 to 01 january 2021 are the same as the seconds passed from 01 december 2019 to 01 january 2021.
Why is this? I've already tried the above code with timezones on 00:00:00+00 timezone for all dates (for 1st january 2021, 1st december 2019 and 2nd december 2021), and it gives the same result
Obviously, I would have expected the epoch to be different, around 3600*24 of difference (seconds in a day).
The similar results come from the age() function which returns an interval with years, months, days. In such an interval, 1 month = 30 days, so their conversions in seconds are similar.
You will get the expected result with
SELECT extract(epoch from ('2021-01-01'::timestamp - '2019-12-01'::timestamp)) => 34300800.000000
SELECT extract(epoch from ('2021-01-01'::timestamp - '2019-12-02'::timestamp)) => 34214400.000000
I have erroneously used Calendar.current.startOfDay(for: Date()) to populate a date attribute in Core Data. This means that when users cross different timezones I may have different dates unintentially stored in the date attribute field e.g.
Timezone 1 - 25th 23:00
Timezone 2 - 25th 22:00
Timezone 3 - 26th 05:00
I need to update the Calendar to use UTC Timezone but I need to also perform a migration so that the existing entries in Core Data read like this…
Result:
Timezone 1 - 26th 00:00
Timezone 2 - 26th 00:00
Timezone 3 - 26th 00:00
What are the steps to perform this migration. If I do a UTC startOfDay on it Timezone 1 would get 25th 00:00 instead of 26th 0:00 which is what it should be. Is it possible to accurately update existing entries?
Edit:
For some context I need a reliable way to get all the entries for the 26th for example. I used startOfDay to store the date as it meant I could query by it too and have the relevant entry returned (at any moment in time get the startOfDay and it will give me the entries for the whole day). For historical dates I can do the same - let's say the user has navigated back 2 days I can take startOfDay and subtract 2 days using Calendar.current.date(byAdding: .day, value: -2, to: date) and query for that.
So now the timezone breaks the above logic but is there some way to fix this? If I loop through the entries I can figure out the date it was supposed to be for and perhaps change the attribute to a string - e.g. 26-05-2021 or start to store day, month, year instead and query that.
From reading your answer Duncan I don't think I want to use UTC calendar as it would start to store the entry against the incorrect date from the users perspective dependent on their timezone e.g. user moves to next day and utc is still on previous.
Edit 2:
In a migration I will take the date that is stored and map it to new day, month and year properties storing those instead by getting them from Calendar.current.dateComponents([.day, .month, .year], from: date). Then instead of query by date I will query by day month and year of the Calendar.current where the user is. The side effect here is there is potential the user adds something for today (27th) changes timezone and sees 26th data but I don't think it can be avoided and the old data will then show as intended.
If you took the current time and used Calendar.current.startOfDay(for: Date()) to calculate midnight in the user's local time zone, you have a loss of information. You don't know what time of day the operation was performed. If you saved the time of day in the local time zone in another field, you could reconstruct a Date in UTC.
It isn't clear that what you did was wrong. The day, month, and year is only meaningful in a specific time zone. I am in the Washington DC metro area. We are in daylight savings time (EDT). It is currently 20:56 on the 26th of May. However, it's 1:56 AM on the 27th of May in London, 2:57 AM in Munich, and 3:57 AM in Tel Aviv. All at the exact same instant in time. In UTC it is 0:57 AM on the 27th of May.
Most people think of the calendar date in their local time zone. That is their frame of reference. If you ask me the date right now, I'll tell you it's the evening of the 26th of May. Unless I know you are in a different time zone, that's the "right" answer to me.
If I start out at midnight on a given day in my time zone, calling Calendar.current.startOfDay(for: Date()) each hour, I'll get midnight that day for all 24 hours in my local time zone. For the first 20 hours of the day, that would be the same result I would get if I created a Calendar in UTC and made the same call. However, at 20:00 EDT, I would start getting the next calendar day if I made the same query in UTC.
If you don't know what time of day you made the call to Calendar.current.startOfDay(for: Date()), there is no foolproof to figure out the day/month year in UTC at the instant you made the call. It depends on the time of day in the local timezone, and that timezone's offset from UTC.
Consider this code:
var calendarUTC = Calendar(identifier: .gregorian)
if let utcTimeZone = TimeZone(identifier: "UTC") {
print("Valid time zone")
calendarUTC.timeZone = utcTimeZone
}
print ("Start of day in UTC is \(calendarUTC.startOfDay(for: Date()))")
print ("Start of day in local time zone is \(Calendar.current.startOfDay(for: Date()))")
That outputs:
Start of day in UTC is 2021-05-27 00:00:00 +0000
Start of day in local time zone is 2021-05-26 04:00:00 +0000
That's because right now, which is 20:56 on 26 May in my time zone, it's 0:56 on 27 May in UTC. So if I ask the UTC calendar for the start of day for now (Date()) I get midnight on 27 May, in UTC.
If I ask the same question of my local calendar, I get midnight on 26 may in my time zone, which is 4:00 AM on 26 May in UTC.
If I ran the same code this morning at 8:00 AM in my time zone, I would have gotten the output:
Start of day in UTC is 2021-05-26 00:00:00 +0000
Start of day in local time zone is 2021-05-26 04:00:00 +0000
(Since at 8:00 AM on 26 May in EDT is also 26 May in UTC.)
It's tricky and not 100% reliable and only works if you know that all days were created using startOfDay. But first you need to decide what you want. Say one date was created at 10pm in the New York, and one at exactly the same moment in London, at 4am the next day. What day do you want to be stored?
If your date stored is 25th, 10pm, then you know it was created in a timezone where the day started at 10pm UTC. You are lucky, there are only two time zones that would have created this, one without DST, one with DST. So you know it happened in one of these two time zones, within 24 hours.
Unfortunately, time zones cover 26 hours. Fortunately, only some islands in the Pacific Ocean have same time and different dates (+13 and -11 hours). For these places, you cannot possibly know which date is correct, but very few people would be affected.
I am working on resolving a timezone issue and just want to understand how to interpret the timezone if I have got it right
2018-01-04 22:31:23.1+00
date time.1+00 ..any simple explanation on how can I know which time zone is this ?
2018-01-04 22:31:23.1+00
Year: 2018
Month: 01 (January)
Day: 04
Hour: 22 (10pm)
Minute: 31
Second: 23.1 (.1 is one-tenth of a second)
Offset: +00 (hours East of GMT)
Note, you cannot determine which time zone this is in - only the offset from UTC/GMT applicable at that timestamp.
Since multiple time zones can use UTC+00, you don't know which of those time zones it is in. It might just be in UTC, but it might be in Atlantic/Reykjavik, or Africa/Casablanca. One uses UTC year round, the other switches between UTC and UTC+1. There are others as well.
I am working with an API that generates time periods based on a configured set of parameters.
So for example, I can specify I want 12 one month periods starting Jan 1st at midnight, and therefore the API will generate 12 monthly periods
01 Jan 2016 00:00:00 – 31 Jan 2016 23:59:59
01 Feb 2016 00:00:00 – 28 Feb 2016 23:59:59
Through to
01 Dec 2016 00:00:00 – 31 Dec 2016 23:59:59
Now the API expects a start date param supplied for the sequence of periods to be an ISO formatted string in UTC. So I’m currently in the UK, therefore if I choose to start the monthly periods from Jan 1st 2016 this would be 2016-01-01T00:00:00Z and is what I supply to the API call I am making to say when the first instance of my monthly periods should begin.
So now if I view the start and end dates of the generated monthly periods via the API, I will see them come back as
2016-01-01T00:00:00Z - 2016-01-31T23:59:59Z
2016-02-01T00:00:00Z - 2016-02-28T23:59:59Z
Etc to
2016-12-01T00:00:00Z - 2016-12-31T23:59:59Z
Something struck me about these generated periods and that is I want them to begin at midnight for where I currently am, but a period that is affected by GMT Daylight Time, so say my April period will look like so in the generated period from the API
2016-04-01T00:00:00Z - 2016-04-30T23:59:59Z
Parsing the start date for the above into a date object for viewing in the client (on my machine) will show up as
Fri Apr 01 2016 01:00:00 GMT+0100 (GMT Daylight Time)
So it’s saying that period starts at 1am and not midnight.
Now say if I wanted 12 months to be generated from 1st Jun when Daylight Savings is in effect.
My client side code currently will supply a start date to the API of 2016-05-31T23:00:00Z. This causes the API to generate start dates for each monthly period as being
2016-05-31T23:00:00Z - 2016-06-31T22:59:59Z (June Period)
2016-06-31T23:00:00Z - 2016-07-31T22:59:59Z (July)
Etc to
2017-04-30T23:00:00Z - 2017-05-31T22:59:59Z (May)
But now for a period that is not in GMT Daylight Time, so Jan for example it will show up as
2016-12-31T23:00:00Z - 2017-01-31T22:59:59Z
Meaning my client will see that start date as
Sat Dec 31 2016 23:00:00 GMT+0000 (GMT Standard Time)
So not Jan 1st at 00:00
Does this suggest that the API should know about the users timezone so the period generation logic in the API can factor this is when calculating the start and end dates?
Maybe I'm over thinking things here?!
The only real question I see here is:
Does this suggest that the API should know about the users timezone so the period generation logic in the API can factor this is when calculating the start and end dates?
In general, the answer is YES. Any time you are mapping calendar dates back to specific instants in time, then by definition you must involve time zones. That time zone can be that of the user's, or of some specific business location, or fixed to UTC, but they indeed part of the logic.
Consider that not every calendar date has a valid local "midnight" in every time zone. An example is 2015-10-18 in Sao Paulo Brazil, where the first moment of that day was 1:00 AM due to their spring-forward daylight saving time transition. There are many other examples of this around the world.
The only way to avoid the problem entirely is to not deal in specific times. If you are only working with whole dates, then your code can certainly compute the exact dates of each month without knowing anything about time zones. 2016-01-01 through 2016-01-31 has no awareness of time or time zone. It's only when you try to ask what the current date is, or if now is within that range, or if some other specific instant in time is within that range that you have to start thinking about time zones.
I'm querying information from a Facebook page for a small business using FQL and I'm trying to parse the business hours. The numbers I am getting back seem to represent seconds but I'm not sure when the epoch is. Wednesday and Thursday are the most confusing - open on Thursday is "57600" which would be 16 hours in seconds which would make 4pm Wednesday the epoch, but the closing hours on Wednesday - far past 4- are in the 600,000+ range.
Mon: 8:15am-12pm and 1pm - 5pm Tue: 8am-12pm and 1pm - 5pm Wed: 8am-12pm and 1pm - 9pm Thur:8am-12pm and 1pm - 5pm Fri:8am-12pm and 1pm - 5pm Sat:8am-12pm and 1pm - 5pm
<hours>
<mon_1_open>404100</mon_1_open>
<mon_1_close>417600</mon_1_close>
<tue_1_open>489600</tue_1_open>
<tue_1_close>504000</tue_1_close>
<wed_1_open>576000</wed_1_open>
<wed_1_close>590400</wed_1_close>
<thu_1_open>57600</thu_1_open>
<thu_1_close>72000</thu_1_close>
<fri_1_open>144000</fri_1_open>
<fri_1_close>158400</fri_1_close>
<sat_1_open>230400</sat_1_open>
<sat_1_close>244800</sat_1_close>
<sun_1_open>0</sun_1_open>
<sun_1_close>0</sun_1_close>
<mon_2_open>421200</mon_2_open>
<mon_2_close>435600</mon_2_close>
<tue_2_open>507600</tue_2_open>
<tue_2_close>522000</tue_2_close>
<wed_2_open>594000</wed_2_open>
<wed_2_close>622800</wed_2_close>
<thu_2_open>75600</thu_2_open>
<thu_2_close>90000</thu_2_close>
<fri_2_open>162000</fri_2_open>
<fri_2_close>176400</fri_2_close>
<sat_2_open>248400</sat_2_open>
<sat_2_close>262800</sat_2_close>
<sun_2_open>0</sun_2_open>
<sun_2_close>0</sun_2_close>
</hours>
If I change it to simply 8am-5pm Monday to Saturday I get an equally confusing response from FB
<hours>
<mon_1_open>403200</mon_1_open>
<mon_1_close>435600</mon_1_close>
<tue_1_open>489600</tue_1_open>
<tue_1_close>522000</tue_1_close>
<wed_1_open>576000</wed_1_open>
<wed_1_close>608400</wed_1_close>
<thu_1_open>57600</thu_1_open>
<thu_1_close>90000</thu_1_close>
<fri_1_open>144000</fri_1_open>
<fri_1_close>176400</fri_1_close>
<sat_1_open>230400</sat_1_open>
<sat_1_close>262800</sat_1_close>
<sun_1_open>0</sun_1_open>
<sun_1_close>0</sun_1_close>
<mon_2_open>0</mon_2_open>
<mon_2_close>0</mon_2_close>
<tue_2_open>0</tue_2_open>
<tue_2_close>0</tue_2_close>
<wed_2_open>0</wed_2_open>
<wed_2_close>0</wed_2_close>
<thu_2_open>0</thu_2_open>
<thu_2_close>0</thu_2_close>
<fri_2_open>0</fri_2_open>
<fri_2_close>0</fri_2_close>
<sat_2_open>0</sat_2_open>
<sat_2_close>0</sat_2_close>
<sun_2_open>0</sun_2_open>
<sun_2_close>0</sun_2_close>
</hours>
Am I missing some defacto standard time representation? How would someone go about parsing this as a legitimate time of day?
The Unix epoch is the time 00:00:00 UTC on 1 January 1970. Any time you see the term "epoch" used in relation to computer-based time, that's usually what it means.
In UTC, 404100 is Mon, 05 Jan 1970 16:15:00 GMT. Or, in the PST timezone, Mon, 05 Jan 1970 08:15:00 PST, which is the time you're expecting. Ignore the date; it's irrelevant, anyways.
You can test what I'm describing using this Epoch Converter.