关于Java等语言中的日期处理

2017年9月21日,Java 9正式发布?


但是今天我要谈论的是Java8中引入的日期和时间API。


历史

Java自从1.0版本就存在java.util.Date类。
Java 1.0发布于1996年。
Date类保存的是自纪元(epoch)以来的毫秒数,不包含时区信息。
由于Date类是可变的,所以经常会发生意外。
如果将Date作为函数参数传递,因为存在可能在函数内部被修改的风险,
有时需要进行防御性复制(defensive copy)后再传递。


日期

import java.text.SimpleDateFormat;
import java.util.Date;

public class Aaa {
   public static void main(String[] args) throws Exception {
       Date today = new Date();
       System.out.println("Today is: " + new SimpleDateFormat("yyyy-MM-dd").format(today));

       // 昨日の日付を表示したいな
       昨日の日付を表示(today);

       // 今日の日付を表示したいな
       System.out.println("Today is: " + new SimpleDateFormat("yyyy-MM-dd").format(today));
   }

   public static void 昨日の日付を表示(Date date) {
       // 昨日の日付を作る
       date.setTime(date.getTime() - 24L * 60 * 60 * 1000);
       System.out.println("Yesterday is: " + new SimpleDateFormat("yyyy-MM-dd").format(date));
   }
}

结果 (jié guǒ) – the result

Today is: 2017-12-19
Yesterday is: 2017-12-18
Today is: 2017-12-18

日历时代

Java 1.1 在1997年引入了 java.util.Calendar。
Java 1.1 是在1997年发布的。
实质上,Calendar 等于 GregorianCalendar。
它是作为 JDK 1.1 国际化支持的一部分引入的。
Calendar 保存了从纪元开始的毫秒数(Date)和时区相关信息。
但它的API设计很糟糕。
同样像 java.util.Date 一样,它是可变的,所以容易出现意外。


我想要制作日本时间2001年12月25日14:00准确的日历,但是…

import java.text.SimpleDateFormat;
import java.util.Calendar;

public class Bbb {
   public static void main(String[] args) throws Exception {
       Calendar cal = Calendar.getInstance();
       cal.set(Calendar.YEAR, 2001);
       cal.set(Calendar.MONTH, 11); // 0 はじまり
       cal.set(Calendar.DAY_OF_MONTH, 25);
       cal.set(Calendar.HOUR_OF_DAY, 14); // Calendar.HOUR を使うとAM/PMがおかしくなる
       cal.set(Calendar.MINUTE, 0);
       cal.set(Calendar.SECOND, 0);
       cal.set(Calendar.MILLISECOND, 0);

       System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ").format(cal.getTime()));
   }
}

漫长的冬天时代

日本的化妆(雅加达)Commons-Lang的DateUtils每天的努力…
也有Joda-Time这个选择
在2003年左右出现的.Net Framework1.1的DateTime已经牢固地成为了Immutable。

顺便提一下,Java 6.0(2006年)新增了处理和历的JapaneseImperialCalendar。


全新的黎明

Java 8.0 (2014年) 加入了日期和时间API。
基于Joda-Time(最早可能是在2002年左右)制定了JSR-310。
以不变性为特点
提供在java.time包中。


日期和时间 API

主要/核心的班级

本地日期

一个保持年月日的类。基于ISO8601标准。使用先进的公历来处理日期。java.util.Date在处理上有朱利历和公历切换的问题。

本地时间

一个用于保存小时,分钟,秒(精确到纳秒)的类。不具备时区信息。

本地日期时间

LocalDate和LocalTime类。

区域编号

保持着亚洲/东京等地理时区信息,之前已经有java.util.TimeZone,但新创建了一个类。不仅可以处理偏移信息,还能保留夏令时信息。为了处理单纯的偏移,存在一个名为ZoneOffset的子类。

立即

含义:瞬间、瞬时、(特定的)时刻

ZonedDateTime: 时区日期时间

本地日期 + 本地时间 + 时区


先创立的公历是指…

「ISO8601 是对1582年10月开始实施的格里高利历制定的一种适用于1582年以前的历法。」

在1582年之前,处理系统的处理方式各异。

ISO8601不提供对公元前1年的处理规定。
Java的LocalDate将公元1年的前一年视为0年来处理。
LocalDate.of(1,1,1).minusDays(1) -> 0000-12-31
Postgres将1年的前一年视为-1年。


在数据库中处理日期

就算是DATE类型,根据不同的DBMS处理方式各不相同。

在标准的SQL中,日期时间相关的数据类型包括:
* DATE类型(日期)
* TIME类型(时间)
* TIMESTAMP类型(日期和时间的组合)
TIME和TIMESTAMP不保存时区信息。


在Oracle中…

日付時間相关的数据类型有四种:
* DATE:保存年月日和时分秒,不包含时区信息。
* TIMESTAMP:保存年月日和时分秒,可指定小数位数(最多9位),不包含时区信息。
* TIMESTAMP WITH TIME ZONE:在上述的基础上添加了时区信息。
* TIMESTAMP WITH LOCAL TIME ZONE:拥有时区信息,但是以数据库的时区为准。

参考链接:http://otndnld.oracle.co.jp/document/products/oracle11g/111/doc_dvd/server.111/E05765-03/datatype.htm#18523

日期在内部以儒略日和秒为单位。7字节。范围从公元前4712年01月01日到公元9999年12月31日。
使用儒略历和格里高利历。
公元1年的前一年是0年,0年的前一年被称为“公元前1年”。


在Postgres中……

    • DATE型(日付)

 

    • TIME型(時刻)

 

    • TIMESTAMP型(日付と時刻を足したもの)

 

    TIMEとTIMESTAMPはタイムゾーンの有り無しを指定できる

与Oracle相同,使用儒略日历公元前4713年1月1日至294276年12月31日。
采用最初的格利高里历法(先行历法)。
公元1年的前一年是公元前1年,公元前1年的前一年是公元前2年。
0001-01-01的前一天是’0001-12-31 BC’.


MySQL被广泛用于数据库管理系统。

    • DATE型(日付)0年月日

 

    • TIME型(時刻) ’00:00:00′ マイクロ秒まで。タイムゾーンない

 

    DATETIME型(日付と時刻を足したもの) タイムゾーンない

在日期中,使用 3 个字节的存储空间。范围从 ‘1000-01-01’ 到 ‘9999-12-31’,采用先行的公历制。


其他


Git 不仅仅是一个版本控制系统。

保留从Epoch开始的秒数和时区信息


Apache Spark 是一个快速、可扩展且易于使用的开源大数据处理框架。

以下是对上述内容的中文表达:

日期时间相关有两种类型:
* TimestampType:保存年月日和时分秒信息,没有时区信息。
* DateType:保存年月日信息。

请参考链接:https://spark.apache.org/docs/latest/sql-programming-guide.html#data-types


镶木地板 mù dì

日付時間相关有三种类型:
– DATE以INT32存储自1970-01-01以来的天数。
– TIME_MILLIS以INT32存储从0:00开始的毫秒数。
– TIMESTAMP_MILLIS以INT64存储自时代开始以来的毫秒数。没有时区信息。


总结

在处理日期和时间时,应该了解每个处理系统的行为。
要考虑时区的存在与否。
即使存在夏令时,也能正常工作吗?
最好设计一个能够在更改处理机的时区时不会出问题的结构。


获取当前日本本地时间
LocalDate.now(ZoneId.of(“Asia/Tokyo”))
ZoneId.getAvailableZoneIds.asScala.foreach(println)
JapaneseDate.of(1900,1,1).getEra

在Oracle中,日期时间相关的数据类型有四种。

我们在内部保持着儒略日。从-4712/01/01到9999/12/31。我们同时使用儒略历和格里高利历。将日期2001-01-01转换为儒略日的值是2451911。

把日期 ‘0001-01-01’ 转换为儒略日,结果为1721424。

将日期’1582-10-04’转换为J格式的字符串输出为2299160,将日期’1582-10-15’转换为J格式的字符串输出为2299161。

在Postgres中,与Oracle一样,使用了儒略日历,从公元前4713年1月1日到公元294276年12月31日。在Postgres中,执行SELECT TO_CHAR(DATE ‘2001-01-01’, ‘J’)命令可以得到结果。

将 to_char 翻译成中文。

2451911(1行)可以转述为:一行中有2451911条数据。

postgres=# SELECT TO_CHAR (DATE ‘0001-01-01’, ‘J’);

将日期 ‘0001-01-01’ 转换为字符表示,使用J模式。

转换成字符

1721426
(1 行)

postgres=# 查询 (日期 ‘1582-10-04’, ‘J’) 的TO_CHAR值;

将to_char转换为字符串

2299150可以翻译成”二百二十九万九千一百五十”。

广告
将在 10 秒后关闭
bannerAds