My rails 3 app needs to interact with an external webservice. This webservice provides information about raining events across the entire US (ultimately the country doesn't matter). The pertinent information is start/end time formatted as ISO8601 including timezone. The server will run on the east coast of the US (so EST, soon to be EDT). All database entries will be stored as UTC.
I need to be able to store the timezone(TZ) in which the event takes place so I present the user with options to view the events in their own TZ or in the originating TZ. Once they reach the location they won't care if the event starts based on their HOME TZ but TZ in which the event will happen.
input data:
start = "2011-04-08T10:00:00-06:00"
end = "2011-04-08T16:00:00-06:00"
#fyi
Time.zone => GMT-05:00 Eastern Time US Canada
# Server time zone, original time zone lost !!!!
Time.parse(start) => 2011-04-08 12:00:00 -0400
# UTC, time zone lost
Time.zone.parse("2011-04-08T10:00:00-06:00") => Fri, 08 Apr 2011 16:00:00 UTC 00:00
I don't see any way (minus manual string manipulation) to get the original, -06:00 TZ (MST). I was really hoping there would be a RoR way get this info ... seems like there should be a way!
If you use Time you will lose information, but if you use DateTime you will be fine:
DateTime.parse("2011-04-08T10:00:00-06:00")
# => Fri, 08 Apr 2011 10:00:00 -0600
The DateTime class is much more robust than Time and can encode a lot more information, though is slower and more memory hungry. Fortunately, performance will not be an issue unless you are spending most of your time manipulating values like this in large batch operations.
Related
I trying to parse a date in ISO 8601 format and some moments aren't clear for me.
For example, I have the next date: 2020-04-16T07:16:34.858215+03:00 in Europe/Moscow timezone.
Does it mean 07:16 in Moscow time or 10:16? I mean do I need to add 3 hours to date or date is in Moscow time already and timezone just shows how it diffs from UTC?
P.S. I tried to find information about it but everywhere is just common format description without details.
The time specified is the local time, so 2020-04-16T07:16:34.858215+03:00 means 7:16am in Moscow, or 4:16am UTC.
Wikipedia has a good example which clarifies things to at least some extent:
The following times all refer to the same moment: "18:30Z", "22:30+04", "1130−0700", and "15:00−03:30". Nautical time zone letters are not used with the exception of Z. To calculate UTC time one has to subtract the offset from the local time, e.g. for "15:00−03:30" do 15:00 − (−03:30) to get 18:30 UTC.
It's really unfortunate that ISO-8601 talks about this as a time zone, when it's only a UTC offset - it definitely doesn't specify the actual time zone. (So you can't tell what the local time will be one minute later, for example.)
how can we convert the GMT to local SQL DATE?
When i store GMT time , then 1 hour is subtracted from this value.
please help me.
Your question is a bit ambiguous as written, but I am guessing that you want to convert a UTC datetime (sometimes called GMT or Zulu time) into a datetime in your local timezone.
You indicate that your local time zone is -1 hour offset from UTC time.
In this case you simply use the DATEADD function:
SET MyTimeLocal = DATEADD(HH, -1, MyTimeGMT)
Note that this will only work so long as your time zone really is one hour before UTC time. If your location uses daylight saving time, this will be wrong as soon as the time changes, and it will be extra wrong when the time to be converted falls in the crack of the clock change.
There are many better ways to do this in general, but to give a general solution we would need to know what version of SQL is being used and what exactly you are trying to accomplish.
Background
I am investigating different use cases of moment.js for a project but am stumped on the issue of daylight savings ending in the fall. Before asking my question, since I want to be clear and provide background for others who have similar questions, let me explain what I am doing and what found with spring daylight savings.
First, I am working with UTC timestamps and America/New_York timestamps. In the US, daylight savings in 2017 begins on March 12 at 2AM (skipping from 2:00:00AM to 3:00:00AM) and ends on November 5 at 2AM (reverting from 2:00:00AM to 1:00:00AM). Since I also always know the target time zone (America/New_York) that I need to convert to, I will not rely upon moment.js to detect my local time zone and instead explicitly specify the time zone I want.
During the spring when daylight savings goes into effect, the time zones that observe daylight savings, like America/New_York, jump forward an hour. moment.js handles this just fine.
For example, if I pass moment.js a UTC timestamp for the time one second before daylight savings goes into effect for America/New_York, it looks like this:
moment('2017-03-12T06:59:59Z').tz('America/New_York').format('YYYY/MM/DD hh:mm:ss a z')
The input above is taken as UTC because of the Z on my timestamp and I am explicitly setting the target timezone with .tz('America/New_York') so that it doesn't use local system time.
Alternatively using moment-timezone I can explicitly set the input time zone as UTC and set the output as America/New_York.
moment.tz('2017-03-12T06:59:59', 'UTC').tz('America/New_York').format('YYYY/MM/DD hh:mm:ss a z')
Either way, the result is 2017/03/12 01:59:59 am EST.
Then, I run the same commands for a moment just one second later. I will just use the format given in the first example above where I specify the time as UTC and then convert it to America/New_York time:
moment('2017-03-12T07:00:00Z').tz('America/New_York').format('YYYY/MM/DD hh:mm:ss a z')
And my result is correct as expected: 2017/03/12 03:00:00 am EDT - due to daylight savings the time skipped ahead by one hour.
I can then use moment-timezone to go back the other way by passing in an America/New_York timestamp and converting it to UTC.
moment.tz('2017-03-12T01:59:59', 'America/New_York').utc().format('YYYY/MM/DD hh:mm:ss a z')
This gives me 2017/03/12 06:59:59 am UTC
And the next moment in the America/New_York time zone, because of daylight savings coming into play, is 03:00:00 so I convert that to UTC...
moment.tz('2017-03-12T03:00:00', 'America/New_York').utc().format('YYYY/MM/DD hh:mm:ss a z')
... and get 2017/03/12 07:00:00 am UTC which looks correct.
An hour was skipped ("lost") in America/New_York time, but moment can detect that and convert it to UTC.
In Summary, for the spring daylight savings change in the US, I can pass a UTC timestamp into either moment.js or moment-timezone and get back a timestamp in another time zone with the correct daylight savings offset also applied. I can also then pass an America/New_York timestamp into moment and get back a correctly converted UTC timestamp.
My Question
Great, so I want to do the same thing when daylight savings ends in the fall and of course it isn't that simple. My hypothesis is that due to daylight savings effectively causing an hour to "repeat", there is no way for moment to know the correct time UTC. In other words, where there was a gap of one hour when daylight savings started, now we have overlap of one hour.
Question (part 1): Is there a way to pass a relative timestamp and time zone into moment and get back the correct UTC time? When I tried this in the examples below, moment skips an hour on the UTC side.
moment.tz('2017-11-05T01:00:00', 'America/Denver').tz('UTC').format('YYYY/MM/DD hh:mm:ss a z') => "2017/11/05 07:00:00 am UTC"
moment.tz('2017-11-05T01:59:59', 'America/Denver').tz('UTC').format('YYYY/MM/DD hh:mm:ss a z') => "2017/11/05 07:59:59 am UTC"
moment.tz('2017-11-05T02:00:00', 'America/Denver').tz('UTC').format('YYYY/MM/DD hh:mm:ss a z') => "2017/11/05 09:00:00 am UTC"
moment.tz('2017-11-05T02:59:59', 'America/Denver').tz('UTC').format('YYYY/MM/DD hh:mm:ss a z') => "2017/11/05 09:59:59 am UTC"
I assume its because time is happening chronologically like in the example below. UTC offset context is not given therefore I assume that moment cant distinguish between the America/New_York timestamps preceded by asterisks:
*2017/11/05 01:00:00 am America/New_York => 2017/11/05 07:00:00 am UTC
*2017/11/05 01:59:59 am America/New_York => 2017/11/05 07:59:59 am UTC
*2017/11/05 01:00:00 am America/New_York => ???
*2017/11/05 01:59:59 am America/New_York => ???
2017/11/05 02:00:00 am America/New_York => 2017/11/05 09:00:00 am UTC
2017/11/05 02:59:59 am America/New_York => 2017/11/05 09:59:59 am UTC
Again, what I want to know is if there is a way around this? Currently the timestamps in the data that I have does not contain UTC offsets.
Question (part 2): If I am presenting data in the America/New_York time zone then is it correct to think that I will essentially have two hours of data points all stuffed into a (seemingly) single one hour period from 01:00:00 to 01:59:59 on November 5, 2017?
Related Topics
There are a few other topics on SO that are related to this but none that I have found pose or answer this same question. I will link a few here for reference:
Moment.js Convert Local time to UTC time does work
Initialize a Moment with the timezone offset that I created it with
It looks like you have thought the problem through and done some basic research. Thanks!
What you are describing is covered in the moment-timezone docs here. If the data isn't available as a UTC offset in your input, there's no way to tell the difference between the first or second occurrence of an ambiguous local time. Moment picks the first occurrence, because time moves in a forward direction, so this is usually the most sensible choice for most scenarios.
The problem is one of ambiguity. Even as just a human being, if I say "1:00 am on November 5th 2017 in New York" you don't know which of two points in time I'm describing.
That said, sometimes you have external knowledge that can help. For example, if you have an ordered set of timestamps containing time that skips backwards, then you know you encountered a fall-back transition. Say I'm recording data at 15 minute intervals in local time:
00:45
01:00
01:15
01:30
01:45
01:00 <--- this one comes next sequentially, but appears backwards, so infer transition
01:15
01:30
01:45
02:00
You'll have to write your own detection logic to compare one value to the next for that scenario. Also note that if you don't have any time that appears to be out of sequence, then you cannot be assured of which occurrence is being described. A "heartbeat" signal can assist with this in some scenarios.
Now how do you choose the second occurrence in Moment without knowing the offsets in advance? Like this:
First, grab the hasAmbiguousWallTime function from here.
Then define another function:
function adjustToLaterWhenAmbiguous(m) {
if (hasAmbiguousWallTime(m)) {
m.utcOffset(moment(m).add(1, 'hour').utcOffset(), true);
}
}
Now you can do this:
// start with the first occurrence
var m = moment.tz("2017-11-05T01:00:00", "America/New_York");
m.format(); // "2017-11-05T01:00:00-04:00"
// now shift it to the second occurrence
if (... your logic, such as wall time going backwards in sequence, etc. ...) {
adjustToLaterWhenAmbiguous(m);
m.format(); // "2017-11-05T01:00:00-05:00"
}
These two functions should probably be hardened and added to moment-timezone, but they should be sufficient for the scenario you describe.
A couple of other minor points:
Instead of moment.tz(s, 'UTC'), consider using moment.utc(s)
Instead of moment.tz(s, 'America/New_York').tz('UTC'), consider
using moment.tz(s, 'America/New_York').utc()
You may want to review the DST tag wiki for visualization of the problem space.
On part two of your question, yes - you'll end up stuffing two hours of data into what could possibly be visualized as a one-hour space. People have this problem with graphs and charts all the time. They graph something with a constant value over local time, then see a zeroing effect in the spring, and a doubling effect in the fall. Even if you tell moment to use the later occurrence, you won't avoid this unless you actually display the graph in UTC instead of local time.
I'm building an application which will be able to send emails at any specific local time to any place in the world.
For example, my daily schedule (localtime):
8:00 AM - Send email to John in Toronto, Canada
9:15 AM Western Standard Time (Australia) - Send email to Bob in Perth, Australia
10:12 PM - Send email to Anas in Rabat, Morocco
I want to be able to execute this code on and Amazon EC2 server in a single location (e.g. São Paulo, Brasil).
I also know that Toronto is in Eastern Standard Time, (UTC - 5h) , but from March 11, 2012 to November 4, 2012, it is in Eastern Daylight Time (UTC - 4h).
I also know that Perth is in Western Standard Time (UTC + 8h), with no daylight savings.
I also know that Rabat is in Western European Time (UTC), but from April 29,2012 to July 20,2012, and August 19,2012 to Sept 30, 2012 it is in in West European Summer Time (UTC + 1h)
To keep track of these combinations of time zone, daylight savings, et cetera, I will, of course insist that all internal server times be in UTC. However, I need some way to keep track of when and how each time-zone jurisdiction switches time zones because of Daylight Savings or (in the case of Rabat) Ramadan, and then adjust my crontabs to accommodate these changes.
Is there an authoritative web service or set of tables somewhere which would help me keep these timezone changes in sync with my desire to deliver emails at the same local time every day to users in different time zones with different switchover dates for daylight savings?
Most programming languages give you access to timezone conversion functions. The most rudimentary ones only work between UTC and the "local" timezone of the server, so you will need a full-featured one, such as pytz for Python that will let you specify a local time with a timezone name (e.g. "America/Toronto") and convert it to UTC for you. Given that, you don't need to worry about the UTC offsets of different timezones (including historical offsets if they've changed) nor DST start end end times: the library will take care of it for you. Just make sure you have the latest database, which comes in the tzdata package.
As for your crontab, you're probably best off if the local timezone on the server that runs cron is UTC, that way you can put UTC times directly in the crontab. On the other hand, depending on the volume of events that you have, I would advice just having cron run your code at regular schedules intervals (such as every 5 minutes) and then your code figures out what events need to be triggered based on the current UTC time and the contents of your database. Then it doesn't matter what the timezone of the server is.
Is there an authoritative web service or set of tables somewhere ...
No, there is nothing "authoritative", but there is something close. It's called the TZ database, and it is currently under the oversight of IANA. Its home page is here.
It is also known as tzdata, zoneinfo, timezonedb, tzdb, the Olson Database, or the IANA Time Zone Database.
There are implementations for just about every language and platform you can imagine. You can read more in the tz-link file from the tzdb, and in the timezone tag wiki, here on StackOverflow.
I finally found out the difference between UTC and GMT by making the effort to look it up on Wikipedia today. Technically speaking it appears that GMT != UTC because you do not know if it is UTC or UT1 being referred to. However practically, people use the terms interchangeably to indicate the same timezone.
A while ago, I suggested that we change the user interface of one of my companies apps to display UTC instead of GMT.
Just to be sure that our database was not calculating the potential seconds difference between GMT and UTC, I ran the below query and verified that they both are just acting as aliases for the same timezone.
select now() AT TIME ZONE 'GMT', now() AT TIME ZONE 'UTC';
timezone | timezone
----------------------------+----------------------------
2009-02-11 08:46:11.643032 | 2009-02-11 08:46:11.643032
(1 row)
What do you think? Do enough users out there understand UTC? Is it better to use the older but more common term? Or should I just do a UTC/GMT?
Normal humans don't need to worry about the few seconds difference between GMT and UTC. The difference only matters to astronomers and time nerds.
I have seen very little software that bothers to make the distinction. Most software ends up using the labels "GMT" and "UTC" interchangeably. Typically it just means "clock time after removing the local time zone offset in exact hours (or half/quarter hours)."
In most cases, nobody will be concerned about the sub-second technical difference between GMT and UTC.
However, writing that the time is expressed in UTC instead of GMT avoids one source of confusion:
Greenwich (and the UK in general) is currently GMT+01:00 because of the daylight saving time (DST).
GMT+01:00 does not mean 1 hour ahead of the time in the UK as one could mistakenly think. Because of the DST, GMT+01:00 is currently the exact time in England.
Stating it as UTC+01:00 helps to avoid this confusion.
Personally, I think of the term UTC before I think of GMT.
I think of GMT before UTC, but I am also living at GMT (+/-0)