Date

Java 时间与日期处理

在 Java 8 之前,我们最常见的时间与日期处理相关的类就是 Date、Calendar 以及  SimpleDateFormatter  等等。不过 java.util.Date 也是被诟病已久,它包含了日期、时间、毫秒数等众多繁杂的信息,其内部利用午夜 12 点来区分日期,利用 1970-01-01 来计算时间;并且其月份从 0 开始计数,而且用于获得年、月、日等信息的接口也是太不直观。除此之外,java.util.DateSimpleDateFormatter 都不是类型安全的,而 JSR-310 中的 LocalDateLocalTime 等则是不变类型,更加适合于并发编程。JSR 310 实际上有两个日期概念。第一个是 Instant,它大致对应于 java.util.Date 类,因为它代表了一个确定的时间点,即相对于标准 Java 纪元(1970 年 1 月 1 日)的偏移量;但与 java.util.Date 类不同的是其精确到了纳秒级别。另一个则是 LocalDate、LocalTime 以及 LocalDateTime 这样代表了一般时区概念、易于理解的对象。

Class / Type Description
Year Represents a year.
YearMonth A month within a specific year.
LocalDate A date without an explicitly specified time zone.
LocalTime A time without an explicitly specified time zone.
LocalDateTime A combination date and time without an explicitly specified time zone.

最新 JDBC 映射将把数据库的日期类型和 Java 8 的新类型关联起来:

SQL Java
date LocalDate
time LocalTime
timestamp LocalDateTime
datetime LocalDateTime

Date

java.util.Date 对象本身不包含任何时区信息,我们无法在 Date 对象上设置时区。一个 Date 对象包含的唯一东西是从 1970 年 1 月 1 日 00:00:00 UTC 开始的“纪元”以来的毫秒数。你可以在 DateFormat 对象上设置时区,告诉它你想在哪个时区显示日期和时间。Date 表示特定的瞬间,精确到毫秒,yyyy-mm-dd hh:mm:ss;Timestamp 此类型由.Date 和单独的毫微秒值组成。yyyy-mm-dd hh:mm:ss.fffffffff

// 默认创建
Date date0 = new Date();

// 从 TimeStamp 中创建
Date date1 = new Date(time);

// 基于 Instant 创建
Date date = Date.from(instant);

// 从格式化字符串中获取
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");

java.util.Date dt=sdf.parse("2005-2-19");

// 从 LocalDateTime 中转化而来
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());

获取与比较

基于 Date 的日期比较常常使用以下方式:

  • 使用 getTime() 方法获取两个日期(自 1970 年 1 月 1 日经历的毫秒数值),然后比较这两个值。

  • 使用方法 before(),after() 和 equals()。例如,一个月的 12 号比 18 号早,则 new Date(99, 2, 12).before(new Date (99, 2, 18)) 返回 true。

  • 使用 compareTo() 方法,它是由 Comparable 接口定义的,Date 类实现了这个接口。

public static void main(String[] args) {
  Date date = new Date(1359641834000L);// 本地时间 2013-1-31 22:17:14 对应的时间戳
  String dateStr = "2013-1-31 22:17:14";
  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
  try {
    Date dateTmp = dateFormat.parse(dateStr);

    // System.out.printIn 默认按照本地时间打印
    System.out.println(dateTmp);
  } catch (ParseException e) {
    e.printStackTrace();
  }
  String dateStrTmp = dateFormat.format(date);
  System.out.println(dateStrTmp);
}

// Fri Feb 01 06:17:14 CST 2013
// 2013-01-31 14:17:14

操作系统是"Asia/Shanghai",即 GMT+8 的北京时间,那么执行日期转字符串的 format 方法时,由于日期生成时默认是操作系统时区,因此 2013-1-31 22:17:14 是北京时间,那么推算到 GMT 时区,自然是要减 8 个小时的;而执行字符串转日期的 parse 方法时,由于字符串本身没有时区的概念,因此 2013-1-31 22:17:14 就是指 GMT(UTC)时间,那么当转化为日期时要加上默认时区,即"Asia/Shanghai",因此要加上 8 个小时。

Calendar

Date 用于记录某一个含日期的、精确到毫秒的时间。重点在代表一刹那的时间本身。Calendar 用于将某一日期放到历法中的互动——时间和年、月、日、星期、上午、下午、夏令时等这些历法规定互相作用关系和互动。我们可以通过 Calendar 内置的构造器来创建实例:

Calendar.Builder builder =new Calendar.Builder();
Calendar calendar1 = builder.build();

Date date = calendar.getTime();

在 Calendar 中我们则能够获得较为直观的年月日信息:

// 2017,不再是 2017 - 1900 = 117
int year =calendar.get(Calendar.YEAR);

int month=calendar.get(Calendar.MONTH)+1;

int day =calendar.get(Calendar.DAY_OF_MONTH);

int hour =calendar.get(Calendar.HOUR_OF_DAY);

int minute =calendar.get(Calendar.MINUTE);

int seconds =calendar.get(Calendar.SECOND);

除此之外,Calendar 还提供了一系列 set 方法来允许我们动态设置时间,还可以使用 add 等方法进行日期的加减。

SimpleDateFormat

SimpleDateFormat 用来进行简单的数据格式化转化操作:

Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
下一页