Database design MySQL和Java,并且有一个时区处理挑战

Database design MySQL和Java,并且有一个时区处理挑战,database-design,timezone,Database Design,Timezone,我正在处理MySQL和Java,并且有一个时区处理挑战 问题是: 数据库服务器位于美国中部。 用户1在墨西哥。 用户2在新加坡 ZoneId zdt_Asia_Singapore = ZoneId.of( "Asia/Singapore" ); ZonedDateTime zdt_Asia_Singapore = ZonedDateTime.ofInstant( instant , zdt_Asia_Singapore ); 用户1根据英国时区输入日期和时间,以提供从伦敦起飞的航班信息 用户2

我正在处理MySQL和Java,并且有一个时区处理挑战

问题是: 数据库服务器位于美国中部。 用户1在墨西哥。 用户2在新加坡

ZoneId zdt_Asia_Singapore = ZoneId.of( "Asia/Singapore" );
ZonedDateTime zdt_Asia_Singapore = ZonedDateTime.ofInstant( instant , zdt_Asia_Singapore );
用户1根据英国时区输入日期和时间,以提供从伦敦起飞的航班信息

用户2应该能够在以下3个选项中的任何一个中查看该文件

  • 用户1在英国时区中输入的日期和时间
  • 根据用户时区的日期和时间
  • 按照UTC的日期和时间
  • 数据库应该如何构造?
    我们应该将用户提供的日期和时间存储在一列中,将时区存储在另一列中,还是可以将日期、时间和时区存储在一列中?

    努力将时间信息始终存储在UTC约定中。这是唯一一个与现实中“发生”的“时刻”1:1对应的时刻

    其余的都是演示/渲染问题

    即使你认为自己没有时区问题,也要这样做。在数据库生命周期的后期,这个问题仍然会出现。

    这是正确的

    下面是所有三个案例的示例代码,以及一些讨论

    数据库类型
    带时区的时间戳
    数据库表列应定义为带时区的SQL标准类型
    时间戳
    (而不是不带时区的
    )。或者类似的,取决于你的数据库。对日期时间的支持在一些较弱(SQLite)和健壮()之间差异很大

    实际上,所有数据库都以UTC格式存储日期时间值(如果它们完全尊重时区的话)。有些保留输入值传递的时区信息,而有些(如Postgres)则在使用该信息将值调整为UTC后放弃该信息

    在UTC中思考、工作和存储 您的业务逻辑和数据存储应使用UTC。因此,只有一个实际的飞行时间,以UTC为单位。对于墨西哥、新加坡和英国的各种表述,我们使用不同的时区往返UTC值

    服务器无关 服务器在美国中部的位置应该是无关的。首先,服务器的时区几乎应始终设置为UTC(或冰岛)。其次,您应该永远不要依赖该设置,因为它是您无法控制的外部性,而且非常容易更改,即使在运行时也是如此!相反,始终在代码中指定所需/预期时区作为参数

    java.time 始终使用类,而不要使用
    java.util.Date
    /
    .Calendar
    /
    java.text.SimpleDataFormat

    java.sql 从数据库中以
    java.sql.Timestamp
    的形式检索航班时间,该时间定义为

    java.sql.Timestamp ts = myResultSet.getTimestamp( … );
    
    作为旧的麻烦的日期时间类的一部分,尽量减少java.sql类型的使用。立即转换为java.time类。
    瞬间
    是UTC时间线上分辨率为纳秒的瞬间

    Instant instant = ts.toInstant();
    
    请注意,所有移动部件都在UTC中:数据库存储、JDBC、
    java.sql.Timestamp
    Instant
    。完全没有时区并发症

    为墨西哥音乐而调整 对于墨西哥的客户,应用他们选择的时区或您认为合适的时区

    ZoneId zdt_America_MexicoCity = ZoneId.of( "America/Mexico_City" );
    ZonedDateTime zdt_America_MexicoCity = ZonedDateTime.ofInstant( instant , zdt_America_MexicoCity );
    
    搜索堆栈溢出,查找有关生成字符串的信息,这些字符串通过使用类及其
    的本地化…
    方法自动本地化为人类语言和文化规范

    适应新加坡 新加坡的客户也是如此

    ZoneId zdt_Asia_Singapore = ZoneId.of( "Asia/Singapore" );
    ZonedDateTime zdt_Asia_Singapore = ZonedDateTime.ofInstant( instant , zdt_Asia_Singapore );
    
    所有三个对象,我们的
    即时
    和一对
    ZoneDateTime
    对象,都表示时间线上的相同的同时时刻

    根据UTC进行调整 对于在UTC工作的航空公司员工,如果您只需要ISO 8601格式的文本表示,并且0、3、6或9位小数位表示秒的小数点,请使用
    即时

    String output = instant.toString();
    
    如果需要其他格式作为文本表示,请在将
    Instant
    转换为格式更灵活的
    OffsetDateTime
    类后使用该包。请注意,存储在的子类中的

    调整数据输入 如果用户在英国时区输入飞行时间,则随后调整为UTC。顺便说一下,不要混淆英国时间和UTC时间。伦敦时间在历史上一直在变化,目前随着夏令时的变化而变化,而UTC从未变化过(除了)

    地方的
    这个答案适用于特定的时刻、特定的日期和时间。如果你指的是墙上的时钟所指的“上午9点”意义上的飞行时间,因为包括夏令时(DST)在内的异常情况,它可能会四处移动,那么这将是另一个讨论。问题说用户正在输入一个特定的日期和时间,因此上述讨论适用。

    您建议使用两个时间和时区字段还是只使用一个?嗯,答案在答案中。你知道UTC到底是什么吗?嗨,欧文,我知道UTC是什么。我的问题是捕捉飞行时间。如果英国人必须输入从美国到新加坡的航班的起飞和到达时间,我不能期望用户转换为本地时区并输入。同样,如果一个在新加坡的人必须查看时间,那么出发时间应该与美国时间相同,而不是新加坡时间。我将继续使用UTC保存的时间,如果与用户配置文件不同,还将使用时区。请参阅类似问题和。
    ZoneId zoneId_Europe_London = ZoneId.of( "Europe/London" );
    ZonedDateTime zdt = ZonedDateTime( 2016 , 1 , 3 , 9 , 0 , 0 , 0 , zoneId_Europe_London );
    Instant instant = zdt.toInstant();
    java.sql.Timestamp ts = java.sql.Timestamp.from( instant );