Java 创建datetime对象以表示实例,而不考虑字符串操作的时区

Java 创建datetime对象以表示实例,而不考虑字符串操作的时区,java,datetime,jodatime,datetime-format,localdate,Java,Datetime,Jodatime,Datetime Format,Localdate,我有以下字符串形式: 月份,格式为01-12 日期的格式为01-31 格式为2019年的年份 时间,我不知道它的形式是否可以包含毫秒,或者只是类似于HH:MM的东西 所有这些都应该表示一个精确的时间戳,即不相对于时区,但例如,如果作为一个简化的示例: 日/月/年时间无论任何时区问题,都应认为它是正确的。我希望我能清楚地解释这一点。 我的问题是:从这些创建LocalTime或类似对象的最佳方法是什么,这样它就不会因为某个locale etc设置而改变,我可以正确地执行任何需要的字符串操作或获得一个

我有以下字符串形式: 月份,格式为01-12 日期的格式为01-31 格式为2019年的年份 时间,我不知道它的形式是否可以包含毫秒,或者只是类似于HH:MM的东西 所有这些都应该表示一个精确的时间戳,即不相对于时区,但例如,如果作为一个简化的示例: 日/月/年时间无论任何时区问题,都应认为它是正确的。我希望我能清楚地解释这一点。
我的问题是:从这些创建LocalTime或类似对象的最佳方法是什么,这样它就不会因为某个locale etc设置而改变,我可以正确地执行任何需要的字符串操作或获得一个历元?

在我看来,你在问的是不可能的或毫无意义的问题

让我们以评论中的例子为例。一名乘客预订了一个航班,航班到达时间为2019年4月25日13:10,地点为İstanbul。根据惯例,到达时间以到达机场的当地时间为准。由于İstanbul位于UTC偏移量+03:00,因此到达时间等于2019-04-25 10:10 UTC

公认的良好做法是在数据库中以UTC格式存储日期和时间。如果您使用的是SQL数据库,通常应将其时间戳与时区数据类型一起使用“with timezone”部分有点假,因为您无法将时间戳与您选择的时区一起存储;总是UTC,但我刚才说这是一个很好的实践,所以这很好

假设您已从用户处获得此输入:25/04/2019 13:10。如果您知道如何将其转换为LocalDateTime,则很容易;下面的代码示例。如果我们不知道时区(如欧洲/伊斯坦布尔或亚洲/伊斯坦布尔)或UTC偏移量(如+03:00),则无法将其存储在UTC中。想象一下,小约翰·多伊(John Doe Jr.)从未坐过飞机,也不知道在到达机场的当地时间给出到达时间的惯例。对他来说,13:10在他自己的时区美国/芝加哥可能是13:10,等于18:10 UTC,在出发时区美国/纽约可能是13:10,等于17:10 UTC,13:10 UTC,在到达时区可能是13:10 UTC或其他什么

现在让我们说,我们确实知道输入是在欧洲/伊斯坦布尔时区。那么转换到UTC是很简单的。我们将时间存储为2019-04-25 10:10 UTC。现在它不会因为计算机或JVM的任何时区设置而改变。与数据库中的其他UTC时间进行比较非常简单,您可以安全地忽略时区。例如,当您需要向用户显示时间时,可以将其打印在票证上,转换为伊斯坦布尔时间13:10或用户想要的时区

除非您使用的是需要大纪元的API,否则不要麻烦大纪元。标准Java纪元定义为1970年1月1日00:00 UTC。请注意,它是在UTC中定义的,因此它是一个定义良好的时间点。历元时间是自历元起秒或毫秒的有符号计数。我们的示例到达时间是从纪元开始的1556187 000秒,因此这是您的纪元时间。正如你所看到的,它并不意味着人类可读性。您不希望在以这种方式表示时间的情况下破译日志文件或运行调试会话。您也不希望对以这种方式表示时间的数据库进行任何查询

远离字符串操作。仅在日期和时间对象中使用日期和时间。当您收到字符串时,将其解析为适当的日期时间对象。只有当您需要将其呈现给用户或将其作为字符串传输到另一个系统时,才可以将其格式化为字符串

Java日期/时间类型 Java为我们提供了以下日期和时间类型:

LocalDateTime是一天中没有UTC偏移量或时区的日期和时间,例如2019-04-25T13:10。因此,它没有定义时间点。 另一方面,瞬间是没有UTC偏移或时区的时间点。所以它没有定义一天中的日期和时间。它以UTC格式打印,例如2019-04-25T10:10Z,并在内部表示为自新纪元以来的秒数和纳秒数。 OffsetDateTime是具有UTC偏移的日期和时间,例如2018-04-25T13:10+03:00。所以这确实定义了一个时间点,并且定义了一天中的日期和时间。 ZonedDateTime是带有时区的日期和时间,例如2018-04-25T13:10+03:00[欧洲/伊斯坦布尔]。所以这也定义了一个时间点,定义了一天中的日期和时间。 它在代码中的外观 到达时间:2019-04-25T13:10

以UTC打印的到达时间点:2019-04-25T10:10:00Z

到达时间UTC:2019-04-25T10:10Z

编辑:正如我所说,在SQL数据库中,您通常希望将日期和时间以UTC格式保存在带有时区的数据类型时间戳列中。德泰酒店 ls取决于您的数据库和JDBC驱动程序。我相信在MySQL和其他DBMS中,类型可能只是时间戳。这是一个典型的例子:

    // Save into a database column of datatype timestamp with time zone
    PreparedStatement insert = yourDatabaseConnection.prepareStatement(
            "insert into your_table (your_timestamp_with_time_zone_column) values (?);");
    insert.setObject(1, arrivalTimeUtc);
    int rowsInserted = insert.executeUpdate();
如果SQLite没有时区或日期时间数据类型,最好将ISO 8601格式存储在字符列中,因为这比数字列中的历元时间更可读。Instant.toString生成您需要的字符串:

    PreparedStatement insert = yourDatabaseConnection.prepareStatement(
            "insert into your_table (your_varchar_column) values (?);");
    insert.setString(1, arrivalTime.toString());
    int rowsInserted = insert.executeUpdate();
Instant.parse将在检索后解析回相同的字符串

    // Convert to arrival time zone, e.g., for printing on ticket
    String arrivalTimeForUser = arrivalTime.atZone(arrivalTimeZone)
            .format(userInputFormatter);
    System.out.println("Formatted arrival time in local time:   " + arrivalTimeForUser);
当地时间格式的到达时间:2019年4月25日13:10

链接 强制阅读: 解释如何使用java.time。 文件
目前这个问题似乎太宽泛了。您将日期存储在哪里?您需要执行哪种类型的字符串操作?请共享您为演示手头的任务而编写的任何代码。您可以将localDateTime对象转换为localDateTimeObj.toInstantUTC.toEpochMilli@米克:这正是问题所在。我将如何正确存储此信息。如果我能正确地将其转换为日期对象,我想我以后应该能够以我需要的任何方式存储/检索,对吗?@arseniyandru:我没有localDateTime对象。我的问题是如何基于这个输入正确地创建这样一个对象创建一个表示日期和时间的LocalDateTime对象很容易。例如,LocalDateTime.of2019、4、7、18、59。但是,要将其转换为自历元起的秒或毫秒,您需要知道时区或UTC的偏移量。我不明白为什么年+月+日+小时+分钟是精确的,而不是相对于任何时区。这对我来说毫无意义。谢谢你的回答。一个问题:在哪里有//Convert to UTC存储在SQL数据库中的例子,不应该以毫秒为单位存储吗?如果你指的是从纪元开始的毫秒,我在“不必担心纪元时间…”一段中试图反驳这一点。细节取决于您的数据库和JDBC驱动程序的功能,或者您使用什么从Java访问数据库。让我困惑的是示例中的OffsetDateTime。这是java特有的,如果我需要将其存储在MySQL时间戳或SQLite int utc time等中,我需要将其转换为其他内容。我的第一个想法是转换为毫秒以适应所有情况。但从你的评论来看,这似乎不是一个好主意?你能给我解释一下吗?是的,谢谢。与其他系统交换的情况如何。例如,从另一个系统接收数据并在本地存储。什么样的格式最适合所有兼容的网络API交换?还有,如果我得到了你,只要我保存UTC+时区,我就可以用它做任何我需要的事情,对吗?后者是正确的。尽可能地交换使用。
    // Save into a database column of datatype timestamp with time zone
    PreparedStatement insert = yourDatabaseConnection.prepareStatement(
            "insert into your_table (your_timestamp_with_time_zone_column) values (?);");
    insert.setObject(1, arrivalTimeUtc);
    int rowsInserted = insert.executeUpdate();
    PreparedStatement insert = yourDatabaseConnection.prepareStatement(
            "insert into your_table (your_varchar_column) values (?);");
    insert.setString(1, arrivalTime.toString());
    int rowsInserted = insert.executeUpdate();
    // Convert to arrival time zone, e.g., for printing on ticket
    String arrivalTimeForUser = arrivalTime.atZone(arrivalTimeZone)
            .format(userInputFormatter);
    System.out.println("Formatted arrival time in local time:   " + arrivalTimeForUser);