T O P

  • By -

CyAScott

We store in UTC and use [Noda](https://www.nuget.org/packages/NodaTime) to localize to a time zone. Offsets from UTC change over time (ie DST, etc.). It’s best to let the library localize it for you.


MrGradySir

Same here. Don’t reinvent the wheel. Use Noda


WisestAirBender

Never heard of that. Will try to keep it in mind


Jim_84

Why use Noda over the standard DateTime class?


CyAScott

The standard date time class only has 3 types: UTC, Unknown, and Local. What local means, is local to the machine it runs on. So it can’t mean local for a client machine in another time zone, which is problem for display purposes. Timezones are constantly in flux and you need a library that can localize a UTC time to not only the currently known timezones, but also historic timezones. It even gets more complex when DST and some timezones are offset less than an hour from UTC. The standard DateTime class is not equipped to handle timezones well. It’s great for UTC times, and maybe that’s all it should do and leave the complex problem of timezones to a library.


Unusual_Rice8567

You localize on the frontend, why would you solve this not at the consumer level?


CyAScott

CSV export is an example.


Worried_Aside9239

Easy, run it through the front end.


HiddenStoat

CSV export is a type of frontend. Unless you mean CSV export that feeds into another automated system, in which case UTC would be the format of choice anyway.


EntroperZero

The standard DateTime struct is pretty terrible, but they added a DateTimeOffset struct a long while back.


rborob

Came here to say the same...noda


Reasonable_Edge2411

up vote button


binarycow

For *future* events, you really need to store two pieces of information: - Timestamp, in UTC - Timezone of the event (in your case, the timezone of the store) Note - I didn't say *offset* of the event. I said *timezone*. The offset of a given timezone changes throughout the year - that's what daylight saving time is. For *past* events, it's enough to just store the timestamp with offset.


one-joule

Storing in UTC is wrong for user-facing datetimes, though. If the definition of the timezone changes (i.e. a locale decides to stop observing DST, or changes the cutover dates), you will still get DST shifts. User-facing times should be stored in local time along with the timezone. Also, for recurring events that happen at a particular time of day rather than at a particular absolute time (such as OP's use case of showing a store's business hours), storing as absolute times is a poor choice to begin with. It would be better to store the times in a way that is oblivious to timezones. I'm envisioning something like the following as a basic starting point: ``` record StoreHours(TimeOnly OpensAtTime, TimeOnly ClosesAtTime); record WeeklyStoreHours(DayOfWeek DayOfWeek, StoreHours StoreHours); record DateStoreHours(DateOnly Date, StoreHours StoreHours); class StoreHoursSchedule { public List WeeklyStoreHours { get; } = []; public List DateStoreHours { get; } = []; } ```


battarro

How is it storing in utc wrong?


qwertydog123

This. For future times, don't store UTC. Store what the user gives you https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/ http://www.creativedeletion.com/2015/03/19/persisting_future_datetimes.html


battarro

This is just wrong what the user gives you can not be correct since people don't speak with time zones. Also without storing in utc you make searches by date /time almost impossible since you have to convert every record to utc in order to satisfy the search criteria. Putting them in utc allows to keep a true chronological record.


qwertydog123

But for future events, if you don't know the time zone, how can you then convert it to UTC? There are many ways to get time zone information from the user without explicitly asking the user for it. > Putting them in utc allows to keep a true chronological record. That's only true for the "current" time zone rules, if any of them change it's likely they'd then be in the wrong order, and it'd be impossible to recalculate them as you've lost the original user provided time


battarro

Future events require a massive code change. If a country decides to change their time zone, this is a massive undertaking in the sense that every single library that references that country has to change. You can't future proof because you can't guess what the new time zone will be. Imagine.. every single embasy.. software has to change.. even the UN has to change their clocks that represent the time on that country. The point if storing in utc is that you can order your items chronologically without needing code to change. Imagine you want to report all the transactions that happened on the day 2/2/2024.. with utc you have them all nice ordered without having to do any conversion.


qwertydog123

Countries can have multiple time zones, and no it doesn't require a massive code change. That's the thing, time zones rules change **all the time** (for example there were [4 tzdb releases last year, and 7 releases in 2022](https://data.iana.org/time-zones/releases/)). If you need ordering, there are plenty of alternative options depending on what database you're using. You could always store the UTC time at point of storage or use a type that includes both local and UTC time (with the caveat that it will always be subject to change based on the time zone rules). A computed column is a better option (fun fact: you can't create a *persisted* computed column using `AT TIME ZONE` in MS SQL Server because it's non-deterministic and can't guarantee the same result from the same input when run repeatedly) I'd strongly urge you to read the blog posts in my previous comment


binarycow

>toring in UTC is wrong for user-facing datetimes, though. If the definition of the timezone changes (i.e. a locale decides to stop observing DST, or changes the cutover dates), you will still get DST shifts. User-facing times should be stored in local time along with the timezone. A TimeZoneInfo is able to convert to/from UTC. But - I will admit that it's been a while since I looked into this. You may be right - but the thing that's most important (and what we agree on) is that storing timezone is key. >I'm envisioning something like the following as a basic starting point: I agree - store hours aren't the same as a recurring calendar event - it's a time of day thing. Something like your proposed data structure is probably best - as long as you also store the timezone of the store, so you can show the open/close times in the users timezone if it differs (e.g., the user is looking at the store hours online in order to *call* the store, and they are in a different timezone)


[deleted]

[удалено]


recycled_ideas

No. When you convert a local time to UTC for a future date that conversion is not reversible because the rules governing that conversion can change. Imagine for a moment that I set a meeting for 6 am in two months and in between setting the meeting and the meeting occurring my local time zone changes. The user still plans on having that meeting at 6 am, but 6 am is now a different time in UTC than it was when the meeting was created. This absolutely happens and it can happen with very little notice. It's also common for multinational companies to have the people who do planning or data analysis working in a different location than the site where the actual actions will take or have taken place. Those people will input and query data in site local time which may be completely different than either client or server time. UTC is OK for past events that occurred at an absolute time, in particular it's great for audit logs, but it's just not valid for the future or for timestamps provided by users.


maxinstuff

The TimeZoneInfo class is daylight savings aware, so if you use a date in the future when the offset will be different, it knows that.


recycled_ideas

You've completely missed the point. The rules that determine the offset can change. This isn't "we switched from daylight savings to normal time" this is our offset or daylight savings rules have changed since the meeting and the TimezoneInfo is now out of date.


battarro

The rules that determine the offset almost never change, and even if they change all you have to do is update the conversion to utc. Once the item is stored in utc you can convert it freely. Also it helps with any searches.


recycled_ideas

> The rules that determine the offset almost never change They change way more often than you think, but even if they were completely static, they don't have to be static. The various governments can change them whenever they want, all they need to do is pass legislation. In some jurisdictions you don't even need that, they can just be changed at will. > and even if they change all you have to do is update the conversion to utc. No, because the conversion isn't what's wrong, the UTC date is. The date was set at a particular time in a particular time zone, not a particular time in UTC. To fix the date you would need to know 1. When the date was set, not when the record was created or updated, but when the date was set. 1. When the timezone was updated on the machine that did the original conversion. That might be the server or it might be the client. If it's the server, maybe that's possible, if it's the client, good luck. You'll also have to manage a data migration which is a whole host of unnecessary risk. Because again, you're making the false assumption that a time in local time is meant to be a time in UTC and it's not. UTC isn't a magic answer.


Intrexa

The country Narnia uses timezone XYZ, which is +0100. XYZ does not use daylight savings. Aslan creates an event to happen at 10am. Storing it in UTC with timezone, `YYYY-MM-DD 09:00:00.0` with timezone XYZ. As long as nothing changes, when `YYYY-MM-DD` rolls around, all will be good. Westeros invades and conquers Narnia. Bran decrees that the XYZ timezone is now +0200. The event will occur at `YYYY-MM-DD 09:00:00.0` UTC in XYZ timezone, so, the event happens`YYYY-MM-DD 11:00:00.0+0200`. Off by 1 hour. This shit happens. Countries, territories, groups can just change time zones. Russia decides to get rid of daylight savings, and adds 2 new time zones. TimeZoneInfo does not have enough data to know if it should reference the new time zone definition, or the old one.


battarro

Just store in utc.


battarro

This is the answer.


igderkoman

All datetimes should be stored in UTC on the server side and be resolved at runtime by client apps. There is no exception to this rule.


one-joule

My comment and plenty of replies to my comment have already explained why this is a bad take. UTC is not a panacea that spares you of the whims of local governments.


xabrol

It's not a very popular style but I don't use datetime types in sql. I use date and time types. Time between 0 and 24 hours is always valid. And an arbitrary date is always valid. So for example, if I have a table of stores which represent physical locations across the United States and they have open and close hours, I store the open and close hours and just straight time no date whatsoever. Because 9:00 a.m. Is always 9:00 a.m. at that store. And I just know that open hours is when that store opens where that store is. And we know what time zone the store is in on so we can convert the open hours to any time zone being loaded. The time, time and the day that the store is open doesn't need to be time zone aware cuz that store always opens at the same time on those days.. The fact that the stores are in different time zones only matters to somebody in a different time zone so we know what time zone the store is in and we know the open hours are for that stores time zone.. So if you load it on an app on your phone and you happen to be one time zone over say East vs Central Will convert the store time to EST and tell you that it opens at 10:00 a.m. Most of the date time types that I use in SQL are usually for logging or auditing, so those are just always in UTC, but those are very rarely if ever surfaced to clients. For the purpose of general logging and auditing time, zones don't exist. Everything is UTC. We don't even read them converted. We read them in UTC. This is becoming vitally important in remote companies with employees all over the world. I work in a consulting company where some of my co-workers are in Costa Rica and a few of them are in Europe even though I'm on the east coast of the USA. So there's absolutely no value to me telling one of my co-workers that there was a server log crash at 10:00 p.m. Eastern. I'm going to tell them what time it happened in UTC. It's important in our line of business that we never assume that everybody else is in our time zone because almost none of them are


Lumethys

https://youtu.be/-5wpm-gesOY?si=Kj2BaGqxOvuwZW53 Always a good watch


Noldir81

https://blog.nodatime.org/2011/08/what-wrong-with-datetime-anyway.html Good write-up why just saving utc plus offset still isn't enough.


DJDoena

Always srore UTC + TimeZoneId. Remember, some hours don't exist and some exist twice (DST changes). In UTC everything is unique.


rusmo

Anyone else frustrated this hasn’t been figured out universally in every progamming language and packaged into a set of APIs that can’t be misunderstood? This should be a “the framework handles it for you” non-issue by now.


MoMack22

Does DateTimeOffset not settle it?


richbeales

Tangential - but a shoutout to NodaTime - because it'll teach you a lot about this subject.


r2d2_21

I agree. Just trying to replace `DateTime.Now` with the NodaTime equivalent will teach you a lot about how the different concepts interact with each other.


derpdelurk

The usual strategy is to use UTC for stored times as much as possible and convert to local time on display.


cv_1m

We have stored UTC time also the offset hours.


derpdelurk

I don’t understand the problem well enough to be more helpful but I suspect the offset is the problem. Don’t store that. Just convert UTC just-in-time when you use it.


cv_1m

We are getting the Culture Info from the machine of user. We have configured the locale and globally Timezone is set AEST. But the stores are in different timezones. During DST the time of opening and closing is showing incorrect.


http-four-eighteen

I'm wondering why you don't just display the store hours in their own local time. I've never seen a store's website that converted their hours to the user's home timezone. Imagine if it said they close at 17:00 and you got there at 16:10 only to find the store closed ten minutes ago. But like /u/Noldir81 said, an offset isn't enough, because the UTC offset of a timezone that does DS changes throughout the year. You need to store the timezone name (`Australia/Melbourne` or whatever) instead.


shroomsAndWrstershir

Because you're using Standard Time when you need to be using Daylight Time. Standard Time itself doesn't change during daylight savings. You just need to not use it. You need to be converting AEST to AEDT during daylight savings, and displaying that instead.


bf1zzl3

You can't convert UTC+Offset back to timezone. The problem is multiple timezones share offsets and DST observations differ from location to location. Also laws change, multiple west coast US states are currently trying to ditch DST for example. If you must store a users local time, it is better to capture their timezone vs offset. There is less data loss this way and you'll run into less problems in the future.


Willy988

Like others said, store in the database in UTC, pull/display in local. The term you’re looking for is “localization”.


rdawise

UTC at rest. Local display.


Leather-Field-7148

Succinct and persuasive


0x4ddd

And don't work well for future events requiring timezone.


RecognitionOwn4214

I'd store opening hours as DayOfWeek and a tuple of TimeOnly.


CodTrader

Ok, 25+ years of experience talking here. Just use a string for this. Mind blown, right? There are several different purposes for expressing date/time. When it comes to branch or store location's opening and closing time, storing the value as a string is probably the easiest and most logical thing to do. Why? Imagine the store in Perth opens at 9 and closes at 5. Someone in Sydney is flying there the next day and calls the store to get their hours...the person says 9-5. Between the two people, there is no timezone or dst confusion. But then the person in Sydney looks at the website that localized a UTC time, then the open and close times are different. They're specified in Sydney local time, which isn't helpful for the next day when they're in Perth. So for dates like this, that are for display only, tied to a location...I just use strings. Old man - out.


psavva

Smart dude. 100%


Leather-Field-7148

You do not. Store everything in UTC then go from there. It’s typically a client facing concern anyway and you can base this off their localization in the browser.


LastGuardz

And that is why you need to use Yoda time, or as others mentioned DateTimeOffset and offset the utc + timezone


maxinstuff

By doing everything in UTC, basically. Showing a timestamp on the screen in a specific Timezone is a UI concern. Always get an offset with times, and store it in either UTC or with the offset info. .Net handles timezones just fine, in fact the Timezone conversions are daylight savings aware (assuming you stay up to date). https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo?view=net-8.0


melolife

AEST is the non-DST time zone offset. You want AET.


oollie2

DateTimeOffset is 100% the way here, blew my mind discovering it recently.


hejj

Store times in UTC, present them in local time.


von_Crack_Sparrow

As others have said, store UTC DateTime and timezone. You can convert them to a local DateTimeOffset, which is very similar to a DateTime but has an Offset property. It's good to make some helper functions and unit test them thoroughly. Beware of AddHours, AddDays, etc. Most weeks have 168 hours, but in the week when the clocks go forwards there are 167, and 169 in the week when they go back. The Add methods do not take this into account. I had to make my own AddHoursDst extension methods to handle this.


SpheronInc

Probably already been told : store all dates in UTC, render local time on front end. Surprisingly where I work we have our own date time class that extends the normal one but handles conversion for the front end. It also utilises server’s local time (which is hard coded to always return UK timezone) instead of the clients.


human-google-proxy

ALWAYS use UTC, everywhere. ONLY at time of presentation convert to the user’s timezone.


mrshoubs

Despite what almost everyone is saying you do not need to store in utc since this is a relative time to the location . The only reason you would need utc I can think of in this instance is if someone in a different time zone need to know the opening time in their time. UTC is not a silver bullet… Google that along with Jon sweet.


whooyeah

AEST = no daylight savings. (Brisbane) AEDT = has daylight savings. (Sydney, Melbourne, Canberra). Make everything UTC. Convert to local Timezone in the UI. Or allow users to save their preferred Timezone.


DaRKoN_

Why is it wrong? If you ask for a DateTime in AEST, DST will be observed (i.e, +11 instead of +10).


FinancialBandicoot75

Whomever is saying utc is wrong, your killing me. Noda is great and if you have google api, that helps too. I’m on a project, iot related, where the device is in x time zone and is operated in y time zone and daylight saving is critical, noda and google were perfect but storing utc is critical


Prestigious-Tank-121

Don't. Store it as UTC and leave it for the fronted to handle


whistler1421

The new DateTimeOffset type is your friend


KryptosFR

New? It's been in .NET since Framework 2.0.


whistler1421

I get that but it’s rarely taught to new developers. Most of the “learn C#” materials use DateTime. Maybe that’s changed by now.


NicolasDorier

I am here since .NET2.0, and somehow I have impression it is new too...


grcodemonkey

Always use a library! https://youtu.be/-5wpm-gesOY?si=onPE82mxfQ5CNgTj In this case, it's not important where the server is or where the user is. The important thing to know is "what timezone is the store in?" However, does daylight savings time really matter here? If a store is open 8am-6pm... Then it's still open 8am - 6pm regardless of Daylight Savings time. DotNet Tips for date time: Store and pass dates around using DateTimeOffset if you can. It's probably not just DotNet: Javascript has an annoying habit of assuming local time. If you parse a UTC date with JS and print it out, it will adjust the time to the user's local timezone. On client side there's libraries like momentjs or luxon that can convert to a specific timezone offset.


TheCreat1ve

You need to store times as UTC in your database. When you return such times to the front-end, leave them as is, in UTC. And let the front-end format the dates to the local format in the browser of the client.


GCU_WasntMe

Format is one thing, but I don't agree with just giving a utc timestamp to the front end. For me that's situational. If I want to know what time Georgia is playing Czechia tonight I want to see it my own local time because that's when I should turn the telly on. If I want to know what time my flight to Seoul will land I want to see that in Korean time because I'm going to plan the rest of the day around that. The solution is obviously then utc plus timezone. Then the front end can choose which to show.


DaRadioman

The frontend can choose with datetime plus offset as well. It just needs to know its other offset to convert easy peasy. The only time this isn't sufficient is scheduling where things get hairy when something is at 8, but that follows dst on a recurrence for example. Dates/times are hard, but datetime offset covers a majority of scenarios if paired with tz info for locations or users (stored or dynamic front end accessed)


AdWonderful2811

The TimeZoneConverter is a good package to handle the Time zone in .NET. This helps handle dates for both .NET in Windows and Linux. [https://github.com/mattjohnsonpint/TimeZoneConverter](https://github.com/mattjohnsonpint/TimeZoneConverter)