Most active commenters

    ←back to thread

    189 points GordonS | 19 comments | | HN request time: 1.375s | source | bottom
    1. zeroimpl ◴[] No.19533112[source]
    I sometimes wish there was an actual "TIMESTAMP WITH TIME ZONE" type that stored the input timestamp as well. Basically, a version that didn't canonicalize the input by converting to UTC. This way, I can easily show timestamps to the user in the time zone they used to input them.
    replies(6): >>19533287 #>>19534038 #>>19534057 #>>19534316 #>>19535066 #>>19541872 #
    2. niftich ◴[] No.19533287[source]
    I frequently wish that datetime libraries and APIs frozen in time and awkward design were given a second pass and redone in the style of Java 8 [1], which is a triumph of clarity after many years of lessons learned. Even putting out a new RFC would help move things along, because I've long felt that RFC 3339 is underspecified [2].

    If datetime libraries were more thoroughly patterned after that of Java 8, there would be less need for the 'misconceptions programmers believe about datetimes' posts, and less need for the 'just use UTC' or 'maybe always-UTC isn't the right advice' posts, because the data-types are thoroughly reflective of their intended use, and their misuse is harder than in other APIs.

    [1] https://docs.oracle.com/javase/8/docs/api/java/time/package-... [2] https://news.ycombinator.com/item?id=12364805

    replies(3): >>19534597 #>>19535194 #>>19535410 #
    3. welder ◴[] No.19534038[source]
    Edit: I'm being downvoted, but I know more than you about timestamps. Check my bio before downvoting.

    You want a column that can store both timestamp and timezone, so why not just have 2 columns? You already have to convert the timestamp into the user's timezone when rendering because the user's timezone can change. Storing timestamps with timezone just complicates things, for ex:

    display_in_user_zone(TIMESTAMP UTC)

    display_in_user_zone(TIMESTAMP_WITH_TIMEZONE)

    The above is exactly the same, but the UTC one will prevent bugs in the long run.

    The only time it's acceptable to store time with timezone is with DATES that do not have a TIME component.

    If you really need to display the timestamp in the timezone the user originally entered, store the original timezone along with every timestamp.

    replies(3): >>19534517 #>>19534530 #>>19535511 #
    4. Figs ◴[] No.19534057[source]
    We needed exactly that functionality at work a few years ago, so, of course, "TIMESTAMP WITH TIME ZONE" got picked for the column in the DB. After a few weeks of people entering data, DST switched over. Eventually someone noticed all the old dates were all off by an hour...

    It really should have been called "TIMESTAMP IN UTC" or "NORMALIZED TIMESTAMP" or something else instead. It's especially dangerous because the results you get back from using it look correct with casual testing and you might not notice that your database is subtly wrong for a long time.

    replies(2): >>19534353 #>>19535060 #
    5. mastazi ◴[] No.19534316[source]
    When you say "timestamp", many programmers think about UNIX timestamps which, by definition, cannot have a timezone, so to those people a "timestamp with TZ" is a bit of an oxymoron. But I understand where you're coming from.
    6. StreamBright ◴[] No.19534353[source]
    Yep, I was wondering if you could create a postgres type that does exactly this. timestamp_utc and timestamp_local. That would make it easier to understand what is going on.
    7. l0b0 ◴[] No.19534517[source]
    The main reason I want the original time zone is that converting to UTC means information loss. And compensating for that information loss is a PITA, because there is no separate time zone type, so now I have to store a bloody shambles of a UTC timestamp, a string corresponding to a time zone, possibly another string corresponding to the time zone database version (https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a...), and rely on every single language interfacing with the database treating timestamps and time zones in compatible ways, which is guaranteed not to be the case for the foreseeable future, and far from trivial to do even close to correctly in most languages. To focus on compatibility with the real world rather than performance databases could for example store all three pieces of information, plus possibly an internal representation purely for ordering and other performance-related purposes, and allow the user to fetch the results using any time zone (defaulting to the server time zone) and time zone database version (again defaulting to the server one). The application layer should not have to do these conversions.
    8. crote ◴[] No.19534530[source]
    And your last sentence is exactly what many people want.

    Let's say I'm writing a calendar application. Naturally, the user wants to enter all events in their own timezone, which in my case is Europe/Amsterdam. So I can just convert that to UTC, and store it along with a timezone string? Well, that's going to break horribly when the EU abolishes summer time next year, because all of those UTC stamps will be wrong!

    The only sane option here is to store local time, and a string representing the timezone, which is what the name "timestamp with timezone" suggests it is. Yes, I could do the conversion manually, but it would be a lot more convenient to have it in the database directly.

    replies(1): >>19535132 #
    9. tofflos ◴[] No.19534597[source]
    I don't know. I don't necessarily think it's a bad wish but I also feel that the API has its' downsides. My impression is that it has caused a fair amount of confusion among Java developers because it forces a more complicated understanding of time upon people who in many cases aren't interested in writing applications that deal with describing events accurately across centuries or with multiple time zones.

    Personally I find the API confusing and arbitrary. Why include a Year class? Why include both OffsetDateTime and ZonedDateTime? What is the difference between Instant and LocalDateTime for my application that doesn't travel across time zones? Why isn't there an Range class with a start and a stop?

    I guess I find "just use UTC" much easier to deal with.

    replies(1): >>19535546 #
    10. GordonS ◴[] No.19535060[source]
    Totally agree, it's one of the reasons I came across and posted this article - I too had assumed the timestampz type stored the time zone. I'm using Postgres with Ngpsql with supports using .NET DateTimeOffset types as parameters, and as you say depending on your DB config everything can actually look as you expect in the DB...
    11. samgaw ◴[] No.19535066[source]
    It sounds like what you're asking for falls under a 'composite type'. So what you could do is something along the lines of:

      CREATE TYPE datetimetz AS (
        dt  timestamptz,
        tz  varchar
      );
    
    Then in your table def you can call your new type to avoid multiple columns:

      CREATE TABLE example (
        id          integer,
        created_at  datetimetz
      );
    12. welder ◴[] No.19535132{3}[source]
    Yes, you're right. Scheduling is one reason to store timestamps with timezone, to prevent information loss.
    replies(1): >>19535989 #
    13. bradleyjg ◴[] No.19535194[source]
    In case anyone isn't aware, Stephen Colebourne was the specification lead for JSR-310 which eventually became java.time.* He had previously written Joda-Time an open source library which prior to the release of Java 8 was the de facto date/time library for Java for about a decade.

    He'd be someone I want on any new RFC effort.

    14. twic ◴[] No.19535410[source]
    Am i right in thinking that in Java 8 terms:

    SQL timestamp == java.time.LocalDateTime

    SQL timestampz == java.time.Instant, but converted into java.time.OffsetDateTime on read

    ?

    That is, neither of them actually stores a timezone. But timezone is a date and time that needs to be interpreted in the context of some separately-supplied timezone, whereas timezonetz is an actual instant in time?

    IME, it's rare to need LocalDateTime. I work in finance. I often need LocalTime, to specify things like "the exchange opens at 07:30 every day", where the timezone is implicitly that of the exchange, and if the exchange moved (lol Brexit), its timezone might change even if its opening time didn't. I also often need LocalDate, mostly when storing or retrieving data in archives organised by date, because we tend to use the local date for that, so that all the data for one session of an exchange, from open to close, is on one date, wherever in the world it is [1]. But i very rarely need LocalDateTime. Perhaps if i worked in calendaring instead, i would use it all the time.

    It's a shame that SQL doesn't have a ZonedDateTime or OffsetDateTime, but as others have pointed out, you can just store a timestamp along with a timezone or offset.

    [1] Actually, it's worse than this, in that we use the trade date, which is sometimes not the same as the local date - for example, on the Chicago Mercantile Exchange, the market for the E-mini S&P 500 future opens at 17:00 and closes at 16:00 the next day [2]. But that entire session is considered to have a trade date of the calendar date it closes on. In the olden days, the market would open at 07:00 and close at 16:00 (so you had an hour before the banks closed to settle any cash movements, or possibly because traders had very big lunches in those days). Trade date was calendar date. But then the 21st century came along, and they decided to open all day. But because there was so much crucial stuff that happened at the close of trading, they did it by moving the open back to the previous evening, rather than moving the close forward.

    [2] https://www.cmegroup.com/trading-hours.html#equityIndex

    replies(1): >>19536361 #
    15. OliverJones ◴[] No.19535511[source]
    Righto. Solicit a time-zone preference from each user, using the zoneinfo naming system ('Asia/Kolkata' or 'America/Indiana/Vincennes') Then accept times from, and render times to, that user in their local time. DBMS timezone settings do a good job of that. When users decline to give a preference, show them UTC until they get tired of it and give you a preference.

    Finally, boycott Oracle's table server. It's horrible in this respect.

    16. twic ◴[] No.19535546{3}[source]
    > My impression is that it has caused a fair amount of confusion among Java developers because it forces a more complicated understanding of time upon people who in many cases aren't interested in writing applications that deal with describing events accurately across centuries or with multiple time zones.

    I think this is spot on, and is the reason why it's so hard to design time libraries, particularly in language standard libraries. How do you allow all users to express what they need, while not requiring any users to express what they do not need?

    Bear in mind that Joda/java.time are still oversimplifying, because they take UTC as their ground truth, which means they can't account for leap seconds. A really thorough time library would take TAI as the ground truth, then have a layer which knew about leap seconds to convert to UTC [1], then a layer which knew about timezones to convert to local times. Not knowing about leap seconds means you can't calculate the time between two Instants accurately - if there is a leap second in the interval, the time will be off by one. However, since most people don't mind about gaining or losing a second every now and then, UTC is a decent tradeoff.

    > Personally I find the API confusing and arbitrary. Why include a Year class?

    So you can't accidentally pass the year and month, which would otherwise both be integers, the wrong way round to a method which takes those, as i did earlier this week.

    > Why include both OffsetDateTime and ZonedDateTime?

    There's a time format which looks like '1918-11-11T11:00+01:00'. You can parse that to an OffsetDateTime, but you don't have enough information to parse it to a ZonedDateTime. Was that Paris winter time, or Lagos standard time? If you wanted to find the exact six-month anniversary of that moment, you would need to know, because it would be at 11:00 local time [2], which could be 1919-05-11T11:00+02:00 in Paris but 1919-05-11T11:00+01:00 in Lagos, and those are different moments in time.

    > What is the difference between Instant and LocalDateTime for my application that doesn't travel across time zones?

    If your application, or one of its users, resides in one of the timezones which have summer and winter times, then you still have two offsets to think about. Every Instant identifies a unique moment in time for you (up to leap seconds!), but a LocalDateTime does not, because there is one hour a year of LocalDateTime values which identify two different moments an hour apart, and one hour a year of values which don't identify anything at all.

    [1] inb4 someone goes off about relativity

    [2] because everyone knows that the armistice was signed at 11 o'clock on the 11th day of the 11th month, so if you rock up and say "bonjour mes amis, le cérémonie de l'anniversaire c'est à 10h" you will get bayonetted

    17. zeroimpl ◴[] No.19535989{4}[source]
    This is exactly why I said in my original post that I sometimes want this - in many cases I don't, but whenever a user has explicitly input the data I'd like to easily be able to return it in the same timezone. I can (and do) store two columns in the database, but I'd prefer the database and JDBC interface natively support this as a single data type.

    Right now, supposing you have two columns, EventTime TIMESTAMPTZ and EventTimeZone TEXT, you'd have to do something like the following in your query to get the data returned to the application properly:

        SELECT (EventTime AT TIME ZONE EventTimeZone) || ' ' || EventTimeZone
    18. niftich ◴[] No.19536361{3}[source]
    PostgreSQL 'TIMESTAMP', for nonextreme values, is the same idea as java.time.Instant -- an absolute point on the timeline stored internally as a number from some epoch -- but whose default textual interface accepts and emits java.time.LocalDateTime values that correspond, but aren't tagged with the UTC zone.

    When you insert into a 'TIMESTAMP', it's as if it did input LocalDateTime(x).atZone(UTC).toInstant(), and saved that; and when you read it, it's as if it does storedInstant.atZone(UTC).toLocalDateTime().

    A 'TIMESTAMPTZ' is stored the same way, but on string output is converted to the session timezone, and an underspecified input is enriched with the session timezone.

    When you insert into a 'TIMESTAMPTZ' it'd take the input OffsetDateTime or ZonedDateTime, or enrich the input with the session zone until one were obtained, call .toInstant(), and save it. On read, it'd do storedInstant.atZone(sessionZone) to obtain a ZonedDateTime, and its default output format only includes the offset.

    LocalDateTime is useful for calendaring, and as an intermediate step when joining a LocalDate and a LocalTime and working towards a Zoned or Instant.

    19. petereisentraut ◴[] No.19541872[source]
    The problem with this is that time zone definitions change, both in the future because of political and administrative changes, as well as in the past, when mistakes are corrected. So a datum like "1st of May 2022 6pm in London" is not a fixed time. And therefore, you can't do any useful computations with this, like what is the time interval between then and the current time, or is this timestamp before, the same, or after, "1st of May 2022 6pm in Madrid". You can't even compare timestamps in the same time zone, because on some days you don't know whether 2am != 3am. Without the ability to do computations or even basic comparisons, such a type wouldn't be very useful in a database.