I'm currently working on a project that requires a user (in their respective time zone) to set a 'cut off' time for certain Notifications that they receive throughout the day. The user will, for instance, say they want no alerts prior to 8:00 AM and no later than 7:30 PM. This user is located in CST (the time zone information for each user is saved) and the 'server' is in EST. The server is where all of the logical decisions occur for which user should be notified, etc.
What would be the best practice to convert the time part only for comparison purposes?
My current thought would be to take the time set by the user, say "7:00 AM", and create a full DateTime object and store that as .ToUniversalTime(). On the server I can convert the DateTime object to Local time and compare the Time portion only.
Does anyone have a 'better' solution or possibly any advice from someone who has tackled a similar issue?
Thanks!
I suggest that you store the minimum time and maximum time as local times, without dates. You will also want to store the users general timezone information, for example "Central Time", not CST or CDT.
When you are ready to make a determination about sending a notification, convert the current UTC time to the user's local timezone and compare the stored time range against the converted time.
Trying to create a full calendar date from stored time information will be problematic in certain cases, specifically for daylight savings changes. By converting from UTC to user's local time for the comparison, that problem will be avoided.
Related
Currently I have an UTC date which I have to convert to different time zone based on where my client time zone is.
This is the code am currently using:
var timezoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timezone);
var clientTime = TimeZoneInfo.ConvertTimeFromUtc(createDateTime, timezoneInfo);
I know this automatically uses the daylight saving time and provide me the current time based on time zone.
I have a boolean which determines whether is daylight saving time is enabled or not. The above method doesn't work well based on my boolean value.
Is there a inbuilt method or code that converts UTC to different time zone without daylight saving time?
It is generally a bad idea to provide a boolean daylight saving time flag in your application at all. Time zones are all about the actual local time in a particular area, and that always includes whether the government that controls that time zone has decided if daylight saving time applies or not. In other words - it's not up to the user, it's up to their government. Microsoft and the IANA time zone community go out of their way to ensure the time zones accurately reflect those governmental decisions.
If you really must do this, you could consider either using the TimeZoneInfo.BaseUtcOffset property, or you could inspect the result of TimeZoneInfo.IsDaylightSavingTime to decide whether to subtract time from the result. However, both approaches suffer from edge cases that will give you errors in cases where the standard time offset has changed unrelated to daylight saving time. Additionally, not all time zones shift by a full hour for DST, there's one that shifts by 30 minutes.
Ultimately, my recommendation would be to keep your code as-is and not try to use that boolean flag. Instead, go back to the UX or wherever that flag originates and remove it.
I'm hesitant to revisit this overly discussed topic, but I created a set of tables to store data and many of the tables included a field named "createdate" designated as "timestamp without time zone". The date/time values fed to these by the code base are always in UTC. It is intended that the UI will be able to control how the data is presented to the user, so some setting would dictate to convert to time zone in the UI.
Some of these timestamps will be for reports, so to display info for the end user. Other times, the values will be used to determine nightly jobs run against the data.
This is a typical is a multi-tenant cloud hosted system with clients across different time zones.
The server should never be moved, although I suppose changing hosting zones is a very remote possibility.
It was written on the .net platform. Not using noda time, just the built in DateTime stuff (for now).
The docs are pretty clear how the timestamp with time zone stores the info:
https://www.postgresql.org/docs/current/datatype-datetime.html
This answer also has good background on the difference in the two main timestamp data types:
https://stackoverflow.com/a/14616640/1905693
This answer also has some good info, but is Java-oriented:
What is the most recommended way to store time in PostgreSQL using Java?
And Josh Berkus has a dated article that was helpful:
https://it.toolbox.com/blogs/josh-berkus/zone-of-misunderstanding-092811
It seems most of these recommend the timestamp with time zone, but in my case, is timestamp without time zone appropriate?
If I did want to rely on pg to do the conversion, would the AT TIME ZONE clause be ok?
From an overall system architecture, is relying on the UI to change presentation a common and reasonable approach? (yeah, this one may be too opinion-flavored for SO's format)
Not a moment
As others said, TIMESTAMP WITHOUT TIME ZONE is the wrong data type.
That type holds only a date with time-of-day, for example noon on January 21st of 2021. But we cannot know if that means noon in Tokyo Japan, noon in Toulouse France, or noon in Toledo Ohio US — three very different moments, several hours apart from one another. So this type cannot represent a moment, is not a specific moment on the timeline.
The TIMESTAMP WITHOUT TIME ZONE type is good for three kinds of use-cases:
Representing multiple moments all known the same in their locality. For example, Acme Corp orders the manager at each factory in Delhi, Düsseldorf, and Detroit, to make an announcement in two days at their local time of noon.
Representing a date and time-of-day where the intended time zone is unknown. I consider this faulty data that should be rejected. But if you insist on writing it to the database, this type would be appropriate.
Booking future appointments where we want to keep the time-of-day even if those pesky politicians change the offset of the time zone(s) in their jurisdiction. These political changes happen surprisingly often. So book an appointment using two columns: TIMESTAMP WITHOUT TIME ZONE in one, and the name of the intended time zone in another. Time zones are named with Continent/Region format such as Africa/Tunis. At runtime, when you need a moment for calendaring, apply the time zone to the date and time to dynamically determine a moment according to the now-current time zone rules. In Noda Time, you would retrieve a LocalDateTime and time zone, to produce a ZonedDateTime for calendaring.
Moments
When you care about moments, specific points on the timeline, use TIMESTAMP WITH TIME ZONE.
In Postgres and many other databases, this type has a bit of a misnomer. The time zone is not actually saved with the date and time. Instead, upon submission to the database, any indicator of time zone or offset-from-UTC is used to adjust to UTC (an offset of zero hours-minutes-seconds). That UTC value is what Postgres writes to the database. And UTC is what Postgres always retrieves from the database.
Beware: Some middleware and tooling has the well-intentioned but very confusing anti-feature of dynamically applying a default time zone to the retrieved value, adjusting from UTC to that time zone. This creates the illusion of that time zone having been saved with the data. But, no, not so. A TIMESTAMP WITH TIME ZONE column stores only UTC values.
Use case examples:
Tracking the moment when a database record was created, modified, or deleted.
Logging for debugging or sysadmin work.
Tracking when a critical contract is signed or comes into effect.
Like you have seen repeatedly in the sources you quote, timestamp with time zone (timestamptz) is the more appropriate choice in all cases where different time zones may be involved.
Internally, storage is the same. But with timestamptz, Postgres already knows where timestamp value applies, while it is just oblivious in this regard with timestamp without time zone (timestamp).
Note that the given time zone is not stored. That's a common misunderstanding. It's only used to compute UTC time. See:
Time zone storage in data type "timestamp with time zone"
AT TIME ZONE is the SQL construct to use to get the corresponding time for a given time zone.
SELECT my_timestamptz AT TIME ZONE 'US/Hawaii';
With timestamp it gets awkward:
SELECT my_timestamp AT TIME ZONE 'UTC' AT TIME ZONE 'US/Hawaii';
Also, when using timestamp any appended time zone information in literals is ignored, which is typically not what you want.
See:
Ignoring time zones altogether in Rails and PostgreSQL
I usually set the timezone of the role I am using?
ALTER ROLE my_db_user IN DATABASE my_database
SET "TimeZone" TO 'UTC';
Seems to help getting the DateTime correctly.
I am building a system that allows a user to specify his/her working hours. This is stored in the database as:
DayOfWeek: Monday
StartTime: 08:00
EndTime: 17:00
This information is relative to the User A, so based on his time zone. Which the user selects in his/her profile e.g. (UTC+00:00) Dublin, Edinburgh, Lisbon, London
What am I trying to Achieve?
User B currently makes a call to a .NET Web API with a Date e.g. 01 Jan 2019.
I need the API to return User A working hours but in User B time zone.
User B can then book that time with User A by making a second call to the API. In this case the booking is stored in UTC date format.
What I Need?
Can someone please provide a suitable solution for this as both User A and User B can have different Time Zones?
In your comments under the question, you said:
the current solution I have is that I store User A’s working hours as start and end times for each day of the week. I also store the users TimeZone. Currently the API will return the Working Times as a JSON Payload with the workers TimeZone. I then display this data for User B and perform the adjustment with User B TimeZone offset using client side JS. When User B decides to book, the request back to the API is done using User A TimeZone setting and then that date time value is converted and stored in UTC format.
This is mostly good, except when you say that you perform the adjustment using User B's time zone offset.
The problem is that many time zones go through different offsets depending on what date and time you are talking about. For example, if in client-side JS you do something like new Date().getTimezoneOffset(), you are getting the user's current offset. It is not necessarily the same offset that should apply for the date in question. More on this under the heading "Time Zone != Offset" in the timezone tag wiki.
Also, you go on to say that the request back to the API is done in user A's time zone (which is fine), but that you then convert and store the time as UTC. Be careful there - you need to retain the intended appointment time. It's fine to know what the UTC time of a specific event might be, but indeed this can change too.
As an example, consider the latest time zone changes that occurred in Morocco. They were planning to end daylight saving time on October 28th 2018, switching the clocks back from UTC+1 to UTC+0. However, on October 26th 2018, with just two days warning, the government announced that they would stay on UTC+1 permanently and abolish daylight saving time. These sorts of short-notice changes are highly problematic, and has happened around the world many times before. I wrote a blog post about them a couple of years back, which is still highly applicable today.
So, if user A was in Morocco, and you stored an appointment for sometime after the change in UTC, well then since the change didn't happen their appointment would now appear an hour shifted on their local calendar.
In such events, if you had retained the intended local time of the event, then you could also have a process to recompute the UTC time based on what current time zone data you have installed. Short notice changes are super hard, but if there had been say a few months notice, then you'd have time to apply updates and correct the times of the events programmatically. If you only stored the UTC time, then you'd not have that ability.
Another way to think about this is that while UTC always keeps ticking forward consistently (except in some cases around leap seconds), human beings don't think in such terms. If I say that I want to meet you at 10 am in some place, the meeting is aligned to the local time of that place - no matter what changes between the time in that place and UTC occur.
Conversely, scheduling a meeting based on UTC is taking it on blind faith that no changes beyond what are currently predicted will happen. Since we aren't able to peer into the future, we really shouldn't be making such assumptions.
(And again, if you'd like help with code, please show what code you've tried in your question. Generally in .NET, one uses the TimeZoneInfo class for this. Here's an overview on how to use it.)
You can take a look at NodaTime, probably best timezone-related library for .NET
The same is achieved using built-in .Net functionality, but there are some tricky rare issues with it, so it is more reliable for use NodaTime.
The back-end is C# and SQL Server.
I save logging activity date times from different time zones in UTC in my DB. I need to populate a globally distributed front end so it localizes the logged UTC time based on where the front end is located, which will be known e.g. PT, ET. It also needs to handle daylight savings time which is where I'm running into difficulty.
As the UTC offset changes based on the time of the year because of daylight savings time, is there a way for me to find out what the UTC offset is in C# given that I know the date/time and the time zone.
is there a way for me to find out what the UTC offset is in C# given that I know the date/time and the time zone
Technically you shouldn't need to find out this information, the underlying system clock/calendar/what-have-you should take care of it. (I'm sure anybody who has worked on date-time logic will attest to the fact that it is non-trivial to say the least.)
Ideally, any time you need to convert a time zone, you have three things:
A DateTime object representing the value to be converted.
A TimeZoneInfo object representing the known current format of the DateTime object (in this case UTC).
A TimeZoneInfo object representing the target time zone.
Given those things, any time you want to display the DateTime to a localized user, you'd use something like TimeZoneInfo.ConvertTime to perform the conversion. This should ideally be done as close to the UI as possible so that backing logic is always consistently performed in UTC.
I have a data table that stores events. Events are saved with local time. I am developing a form, where the user inputs a date and time in the past. After filling out the form handful of times, I need to take those dates and times, and find the events that occurred at those times.
The problem is that the user is imputing their local time, not mine. I can add a offset, or timezone selection. But then I realized that Day Light savings time is going to make things not work.
I cannot change my data table date and time values. Where I can convert their date and time to mine, while taking in consideration daylight savings?
Thanks
Premise: I really think the ideal way to solve your problem is convert your stored datetimes to UTC, and then use that when you search.
But you said you can't change those, so using ConvertTime to convert them at request time is probably your best second option.
Here you can find all the details you need.
You might also want to give a look at Noda Time, which is quite useful when dealing with TimeZones and DateTime.
As you are storing the event time as local time, you will always have problems with daylight savings time. For events where the time overlaps, it's impossible to tell if the event occured the first or second time that the local time had that value. You have already lost information by storing it as local time. If you would store the event time as UTC instead, it would be possible to avoid that daylight savings problem.
Without changing the data that you store, it's impossible to get around the daylight savings problems. The best you can do is to convert the time from the user's time zone to UTC, then to your local time. Example:
TimeZoneInfo TimeZone = TimeZoneInfo.GetSystemTimeZones().Where(t => t.StandardName == "W. Europe Standard Time").Single();
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(inputTime);
DateTime local = utc.ToLocalTime();
Perhaps something like MyDateTime.ToLocalTime() will work for you?
Check out the following article, it should help.
https://msdn.microsoft.com/en-us/library/ms973825.aspx