Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for a custom ZoneId in exposed-java-time #1473

Closed

Conversation

MrPowerGamerBR
Copy link
Contributor

@MrPowerGamerBR MrPowerGamerBR commented Mar 15, 2022

This implements a ZoneId parameter for date related parameters in exposed-java-time. Currently Exposed uses the current system timezone, which can cause issues if you are inserting/selecting/etc dates in multiple machines that have different timezones.

Before

Currently it is 16:25:40 in America/Sao_Paulo's (UTC-03) time zone.

    transaction {
        val now = Instant.now()

        SchemaUtils.createMissingTablesAndColumns(ActionTimezone)

        TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
        val t1 = ActionTimezone.insertAndGetId {
            it[ActionTimezone.time] = now
        }

        // Let's suppose that this is a different machine in "America/Sao_Paulo"'s time zone executing this code.
        // Keep in mind that Instants do not care about the time zone so it *should* be the same time no matter what.
        TimeZone.setDefault(TimeZone.getTimeZone("America/Sao_Paulo"))
        val t2 = ActionTimezone.insertAndGetId {
            it[ActionTimezone.time] = now
        }

        println("t1: ${ActionTimezone.select { ActionTimezone.id eq t1 }.first()[ActionTimezone.time]}")
        println("t2: ${ActionTimezone.select { ActionTimezone.id eq t2 }.first()[ActionTimezone.time]}")
    }

...

object ActionTimezone : LongIdTable() {
    val time = timestamp("time_utc")
}

Output

t1: 2022-03-15T22:25:40.218714Z
t2: 2022-03-15T19:25:40.218714Z

After

Currently it is 16:27:01 in America/Sao_Paulo's time zone.

...

object ActionTimezone : LongIdTable() {
    val time = timestamp("time_utc", ZoneId.of("UTC"))
}

Output

t1: 2022-03-15T19:27:01.811412Z
t2: 2022-03-15T19:27:01.811412Z

I haven't fully tested it yet, but...

  • It does work on PostgreSQL
  • The tests in TeamCity do pass.
  • My computer uses America/Sao_Paulo as the timezone, and the h2 and SQLite tests ran without any issues, even with the timezone modifications made in the tests to use UTC instead of my local timezone.

However it won't work if you are using a JDBC driver that does not support getting LocalDateTime. So I'm not sure if I still need to change more stuff. (Maybe add a fallback if the JDBC driver does not support it? I already had to add a fallback for the SQLite dialect.)

Fixes #1356
Fixes #1305
Fixes #886

This does not use the timestamp with timezone type that some databases support (example: PostgreSQL)! The ZoneId is used to format the timestamp in your desired timezone.

This does undo a lot of the things done in #1464 because we need to store a ZoneId for date formatting.

If this is good enough, I could try fixing exposed-kotlin-datetime later 😊.

While we could default timestamps to UTC, the timestamp without time zone means just that: It is a timestamp without a time zone, not a timestamp in UTC, it is up to the application/developer to know what is the proper time zone of the timestamp.

For some reason the exposed-kotlin-datetime tests are failed, but I haven't even touched it... weird
@MrPowerGamerBR MrPowerGamerBR marked this pull request as ready for review March 15, 2022 19:10
@MrPowerGamerBR MrPowerGamerBR marked this pull request as draft March 15, 2022 20:14
@MrPowerGamerBR
Copy link
Contributor Author

MrPowerGamerBR commented Mar 15, 2022

After thinking about it, I don't think this is the correct fix for this issue. The issue only seems to affect the timestamp field so we don't need to require a ZoneId for every other type.

However there isn't a clean solution for the issue. There are two solutions:

  • Require the user to provide a ZoneId for the timestamp, because we need to format the date in a specific time zone to avoid issues. But timestamps.
  • Use a "TIMESTAMP WITH TIMEZONE" field, but that's only supported in some dialects, like PostgreSQL: https://stackoverflow.com/a/6627999/7271796

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant