一、时间
(1)就目前来说,即使标注为GMT(无论是文件说明,或者是 API的日期时间字符串描述),实际上谈到时间指的是UTC时间。
(2)秒的单位定义是基于TAI,也就是铯原子辐射振动次数。
(3)UTC考虑了地球自转越来越慢而有闰秒修正,确保UTC与UT相差不会超过0.9秒最近一次闰秒修正在北京时间2017年1月1日7时59分59秒(时钟显示07:59:60)出现。这也是本世纪的第五次闰秒。
(4)Unix时间是1970年1月1日00:00:00为起点而经过的秒数,不考虑闰秒,不少来自于Unix的系统、平台、软件等,也都选择这个时间作为时间表示法的起算点。
二、时间轴上瞬间的date
如果想要取得系统时间,方法之一是使用System.currentTimeMillis()方法,返回的是1ong类型整数,代表1970年1月1日0时0分0秒0毫秒至今经过的毫秒数,也就是时间起点与前面谈到的Unix时间起点是相同的,以此方法取得的是机器的时间观点,代表着时间轴上的某一瞬间,然而这一长串 epoch毫秒数不是人类的时间观点,对人类来说没有阅读上的意义。有人会使用Date实例来取得系统时间描述,不过Date也是偏向机器的时间观点。
Date有两个构造函数可以使用,一个可使用epoch毫秒数构建,另一个为无自变量构造函数,内部亦是使用System.currentTimeMillis()取得epoch毫秒数,调用getTime()可取得内部保存的epoch毫秒数值。
Date实例一般只建议用来当作时间轴上的某一瞬间,也就是1970年1月1日0时0分0秒至今经过的毫秒数,其他对时间日期字段的设定与取得,建议通过稍后会介绍的Calendar来进行。
三、格式化时间日期的DateFormat
有关字符串时间格式的处理,职责落到了java.text.DateFormat身上,DateFormat是个抽象类,其操作类是java.text.SimpleDateFormat,你可以直接构建SimpleDateFormat实例,或是使用DateFormat的 getDateInstance()、getTimeInstance()、getDateTimeInstance()等静态方法,用较简便方式按不同需求取得SimpleDateFormat实例。直接构建SimpleDateFormat的好处是,可使用模式字符串自定义格式。
SimpleDateFormat还有个parse()方法,可以按构建SimpleDateFormat时指定的格式,将指定的字符串剖析为 Date实例。
四、处理时间日期的 Calendar
Date 现在建议作为时间轴上的瞬时代表,要格式化时间日期则通过DateFormat,如果想要取得某个时间日期信息,或者是对时间日期进行操作,可以使用Calendar实例。
Calendar是个抽象类,java.util. GregorianCalendaz是其子类,操作了儒略历与格里高利历的混合历,通过Calendar 的 getInstance()取得的 Calendar 实例,默认就是取得GregorianCalendar 实例。例如:
Calendar calendar = Calendar.getInstance ();
取得calendar 实例后,可以使用getTime()取得 Date实例,如果想要取得年月日等日期时间字段,可以使用get()方法并指定 Calendar上的字段枚举常数。例如,想取得年、月、日字段的话:
out.println(calendar.get (Calendar. YEAR)); // 2014 out.println(calendar.get (Calendar.MONTH)); // 3
out.println(calendar.get(Calendar.DATE)); // 30
如果你要设定时间日期等字段,不要对 Date设定,应该使用Calendar,同样地,月份的部份请使用枚举常数设定。例如:
Calendar calendar = Calendar. getInstance() ; calendar.set (2014,Calendar.MAY,26); //2014/5/26 out.println(calendar.get (Calendar. YEAR)); //2014 out.print1n (calendar.get (Calendar.MONTH));// calendar.MAY 的值 4 out.printLn (calendar.get (Calendar. DATE)); // 26
在取得一个calendar的实例后,可以使用add()方法,来改变Calendar的时间。例如:
calendar.add (Calendar. MONTH,1); //Calendar的时间加1个月 calendar.add (Calendar. HOUR,3); //Calendar的时间加3小时 calendar.add (Calendar. YEAR,-2); //Calendar的时间减2年 calendar.add (Calendar. DATE,3); //Calendar的时间加3天
想要比较两个Calendar的时间日期先后,可以使用after()或before()方法。
五、设定Timezone
如果你想要取得指定时区的TimeZone实例,可以使用ID字符串,例如:
TimeZone taipeiTz =Timezone.getTimeZone ("Asia/Taipei");
TimeZone copenhagenTz = TimeZone.getTimeZone ("Europe/Copenhagen“);
可用的ID可以使用TimeZone. getAvailableIDs()来取得,它会返回String1]。Calendar在调用 getInstance()时,可以指定TimeZone,如果已经取得
Calendar实例,也可以通过
setTimeZone()方法设定TimeZone,例如,想知道现在哥本哈根的时间,可以如下:
import java.util.*; import static java. lang. System. out; public class TimeZoneDemo2{ public static void main(String[] args) { TimeZone taipeiTz = TimeZone.getTimeZone ("Asia/Taipei"); Calendar calendar = Calendar.getInstance(taipeiTz); showTime(calendar); TimeZone copenhagenTz = TimeZone.getTimeZone("Europe/Copenhagen"); calendar.setTimeZone (copenhagenTz); showTime (calendar); } static void showTime (Calendar calendar) { out.print(calendar.getTimeZone ().getDisplayName()); out.printf(" %d:d%n" , calendar.get(Calendar. HOUR), calendar.get (Calendar.MINUTE)); } }
六、JDK8新时间日期 API
(一)JDK8 新时间日期处理 API 中最重要的,就是清楚地将机器对时间的概念与人类对时间的概念区隔开来,让机器与人类对时间概念的界线变得分明。新时间日期处理API的主要套件命名为java.time。对于机器相关的时间概念,设计了Instant类,用以代表自定义的Java epoch(1970年1月1日)之后的某个时间点历经的毫秒数,精确度基本上是毫秒,但可添加奈秒(nanosecond)精度的修正数值。
可以使用Instant 的静态方法 now(取得代表 Java epoch毫秒数的 Instant 实例,ofEpochMilli()可以指定Java epoch毫秒数,ofpochSecond()则可以指定秒数,在取得 Instant实例后,可以使用plusSeconds()、plusMillis()、plusNanos()、minusSeconds ()、minusMil1is()、minusNanos()来做时间轴上的运算,Instant 实例本身不会变动,这些操作都会返回新的Instant实例,代表运算后的瞬时。
在新旧API兼容上,如果你取得了Date实例,而你想要改用Instant,则可以调用 Date实例的toInstant()方法来取得,如果你有个 Instant实例,可以使用 Date的静态方法from()转为Date。
(二)人类时间观点的API
人类在时间的表达上有时只需要日期,有时只需要时间,有时会同时表达日期与时间,而且通常不会特别声明时区,也很少在意日光节约时间,可能只会提及年、月、年月、月日等,简而言之,人类在时间概念的表达大多是笼统、片段的信息。
<一>1.LocalDateTime、LocalDate和 LocalTime
对于片段的日期时间,JDK8新时间与日期 API有 LocalDateTime(包括日期与时间)、LocalDate(只有日期)、LocalTime(只有时间)等类来定义,这些类基于IS0 8601年历系统,是不具时区的时间与日期定义。
LocalDateTime、LocalDate、LocalTime等类名称开头为Local,表示它们都只是对时间的描述,并没有时区信息,然而,对于LocalDate,如果设定了不存在的日期,例如 LocalDate.of(2014,2,29)会抛出DateTimeException,因为2014年并非闰年,不过,对于 LocalDateTime.of (1975,4,1,0,0,0),由于没有时区信息,程序无从判断这个时间是否不存在,就不会抛出DateTimeException。