【问题标题】:convert java.util.Date to datastax's LocalDate将 java.util.Date 转换为 datastax 的 LocalDate
【发布时间】:2018-07-15 01:13:48
【问题描述】:

我正在尝试将 yyyy-MM-dd 字符串格式的日期转换为 datastax 的 LocalDate。我正在使用以下代码来做到这一点。

private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

public static LocalDate getDate(String date) throws ParseException {
    Date d = DATE_FORMAT.parse(date);
    return LocalDate.fromMillisSinceEpoch(d.getTime());
}

当我测试这个方法时,我没有得到预期的结果。

public static void main(String[] args) throws ParseException {
    System.out.println(getDate("2017-11-22"));
}
// Actual Output:
2017-11-21
// Excpected Output:
2017-11-22

这里有什么我遗漏的吗?

【问题讨论】:

  • Date d 输出什么?
  • 时区问题。当您所在时区的 11 月 22 日 00:00:00 时,UTC 仍然是 11 月 21 日,我希望 LocalDate.fromMillisSinceEpoch() 使用它,因为您没有告诉它时区。
  • 日期 d 给出Wed Nov 22 00:00:00 IST 2017 输出。我检查了它在 JavaScript 中的纪元值,它也给出了Wed Nov 22 2017 00:00:00 GMT+0530 (IST)
  • SimpleDateFormat 类早已过时并且出了名的麻烦。对于您的任务 java.time,现代 Java 日期和时间 API 显然更适合,所以我建议您使用它而不是 DateSimpleDateFormat
  • Ole V.V. 的解决方案比我的更优雅...我总是忘记新的 Date API...

标签: java date cassandra datastax localdate


【解决方案1】:

TL;DR

public static LocalDate getDate(String date) {
    java.time.LocalDate jtld = java.time.LocalDate.parse(date);
    return LocalDate.fromYearMonthDay(jtld.getYear(), jtld.getMonthValue(), jtld.getDayOfMonth());
}

java.time

您使用的 Java 日期和时间类 DateSimpleDateFormat 早已过时且设计不佳,尤其是后者已被证明很麻烦。此外,现代 Java 日期和时间 API java.time 提供了一个也称为 LocalDate 的类,它比过时的 Date 类更符合您的需求。 java.time.LocalDate 是没有时间的日期。因此,使用它完全消除了导致您的问题的时区问题。您的字符串 2017-11-22 采用 ISO 8601 格式,LocalDate 将其解析为默认格式,即没有任何显式格式化程序,这也使您的任务更轻松。

你的代码出了什么问题?

您的 SimpleDateFormat 实例默认使用 JVM 的时区设置(可能是亚洲/加尔各答时间),因此会将您的日期字符串解析为相当于 Wed Nov 22 2017 00:00:00 GMT+0530 (IST) ,这又与 2017 年 11 月 21 日 18:30 UTC 的时间点相同。 LocalDate.fromMillisSinceEpoch() 的文档说:“如果给定的数字不对应于整数天数,它将向 0 舍入。”换句话说,它四舍五入到 2017-11-21。

如果你真的坚持要坚持老式的SimpleDateFormat,祝你好运(对不起,你可能需要它)。如果是这样,请为其分配 UTC 时区,它将解析为 UTC 日期,并且无论 JVM 的时区设置如何,您现有的方法都将起作用。

private static final SimpleDateFormat DATE_FORMAT = buildOldfashionedDateFormatInstance();

private static SimpleDateFormat buildOldfashionedDateFormatInstance() {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    dateFormat.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
    return dateFormat;
}

链接

【讨论】:

    【解决方案2】:

    类似:

    public static LocalDate convertDate(final String date) {
        String[] arr = date.split("-");
        if (arr.length != 3)
            return null;
        return LocalDate.fromYearMonthDay(Integer.parseInt(arr[0]),
                Integer.parseInt(arr[1]),
                Integer.parseInt(arr[2]));
    }
    

    【讨论】:

      【解决方案3】:

      我的第一个猜测是,由于您约会的时区,有些混乱。要检查这一点,只需打印结果的小时和分钟。如果是这样的,我不会感到惊讶 2017-11-21 23:00

      您可以通过确保日期不会因为“时区差异很小”而发生变化来简单地修复它。

      为了确保您的日期相差几个小时不会弄乱您可以这样做的日期(仅当您对日期的时间部分不感兴趣时​​

      替换:

      return LocalDate.fromMillisSinceEpoch(d.getTime())
      

      按(添加 12 小时以确保几个小时 +/- 不会改变一天)

      return LocalDate.fromMillisSinceEpoch(d.getTime()+1000*60*60*12)
      

      【讨论】:

      • 我同意你的诊断。您的解决方案很脆弱。用户的时区可能是 UTC+13:00 或 +14:00,在这种情况下增加 12 小时是不够的。它也可能在另一边,在 UTC-13:00 或 -14:00,在这种情况下,增加 12 小时将给您第二天(预计 11 月 22 日是 11 月 23 日)。最好将用户的时区显式转换为 UTC。
      • 日期 d 给出Wed Nov 22 00:00:00 IST 2017 输出。我检查了它在 JavaScript 中的纪元值,它也给出了Wed Nov 22 2017 00:00:00 GMT+0530 (IST)
      • @Ole V.V:我同意它很脆弱。因此,只有在您确定它符合您的需求时才使用它。我以这种方式解决了类似的问题,但我可以确定所有日期都在 UTC+1:00 中。 (以及冬季额外的 1 小时偏移)。
      • 假设是危险的。至少应该检查您的程序将始终在 UTC+1 或 +2 或始终在 UTC+05:30 运行的假设,以便您可以确保您的程序崩溃而不是给出不正确的结果,如果假设有一天中断.当然你可以查看 JVM 的时区,但我的口味已经开始变得复杂了……
      猜你喜欢
      • 2019-07-22
      • 2011-08-01
      • 2020-01-04
      • 2022-01-02
      • 2018-03-12
      • 1970-01-01
      • 2014-02-10
      • 2011-08-29
      • 2019-08-03
      相关资源
      最近更新 更多