Date
Date 表示距离1970-01-01 00:00:00的毫秒数,值与时区无关。toString时用本地时区输出,如Thu Jun 30 17:12:57 CST 2016,CST表示China Standard Time。
public Date()
当前时间,例如,System.out.println(new Date());//Thu Jan 01 08:00:00 CST 1970 CST表示UTC+8,所以是8点
public Date(long date)
分配Date对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数。
大部分Date的方法都过时了,由Calendar类的方法替代,以下是几个重要的方法:
public boolean after(Date when)
测试此日期是否在指定日期之后。
public boolean before(Date when)
测试此日期是否在指定日期之前。
public int compareTo(Date anotherDate)
比较两个日期的顺序。
如果参数Date等于此Date,则返回值0;如果此Date在Date参数之前,则返回小于0的值;如果此Date在Date参数之后,则返回大于0的值。
public boolean equals(Object obj)
比较两个日期的相等性。当且仅当参数不为null,并且是一个表示与此对象相同的时间点(到毫秒)的Date对象时,结果才为true。
因此,当且仅当getTime方法对于两个Date对象返回相同的long值时,这两个对象才是相等的。
public long getTime()
返回自1970 年 1 月 1 日 00:00:00 GMT以来此Date对象表示的毫秒数。
public void setTime(long time)
设置此Date对象,以表示1970 年 1 月 1 日 00:00:00 GMT以后time毫秒的时间点。
TimeZone
TimeZone表示时区偏移量,也可以计算夏令时。 通常,使用getDefault获取TimeZone,getDefault基于程序运行所在的时区创建TimeZone。例如,对于在日本运行的程序,getDefault基于日本标准时间创建TimeZone对象。 也可以用getTimeZone及时区ID获取TimeZone。例如美国太平洋时区的时区ID是"America/Los_Angeles"。因此,可以使用下面语句获得美国太平洋时间TimeZone对象:TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
可以使用getAvailableIDs方法来对所有受支持的时区ID进行迭代。可以选择受支持的ID来获得TimeZone。如果想要的时区无法用受支持的ID之一表示,那么可以指定自定义时区ID来生成TimeZone。自定义时区ID的语法是:
NormalizedCustomID:
GMT Sign TwoDigitHours : Minutes
Sign:下面之一
+ -
TwoDigitHours:
Digit Digit
Minutes:
Digit Digit
Digit:下面之一
0 1 2 3 4 5 6 7 8 9
例如,TimeZone.getTimeZone("GMT-8").getID()返回"GMT-08:00"。 Hours必须在0至23之间,Minutes必须在00至59之间。"GMT+10"和"GMT+0010"分别意味着比GMT提前10小时和10分钟。
为了与JDK1.1.x兼容,一些三字母时区ID(比如"PST"、"CTT"、"AST")也受支持。但是,它们的使用被废弃,这是因为相同的缩写经常用于多个时区(例如"CST"可以是美国的"Central Standard Time"和"China Standard Time"),但是 Java平台只可以识别其中一种。
例如:
public static void main(String[] args) {
TimeZone timeZone = TimeZone.getDefault();
System.out.println(timeZone.getDisplayName(true, TimeZone.LONG));//中国夏令时
System.out.println(timeZone.getDisplayName(false, TimeZone.LONG));//中国标准时间
System.out.println(timeZone.getDisplayName(true, TimeZone.SHORT));//CDT
System.out.println(timeZone.getDisplayName(false, TimeZone.SHORT));//CST
System.out.println(timeZone.getID());//Asia/Shanghai
TimeZone timeZone1 = TimeZone.getTimeZone("AST");
System.out.println(timeZone1.getDisplayName(true, TimeZone.LONG));//阿拉斯加夏令时
System.out.println(timeZone1.getDisplayName(false, TimeZone.LONG));//阿拉斯加标准时间
System.out.println(timeZone1.getDisplayName(true, TimeZone.SHORT));//AKDT
System.out.println(timeZone1.getDisplayName(false, TimeZone.SHORT));//AKST
System.out.println(timeZone1.getID());//AST
TimeZone timeZone2 = TimeZone.getTimeZone("America/Los_Angeles");
System.out.println(timeZone2.getDisplayName(true, TimeZone.LONG));//太平洋夏令时
System.out.println(timeZone2.getDisplayName(false, TimeZone.LONG));//太平洋标准时间
System.out.println(timeZone2.getDisplayName(true, TimeZone.SHORT));//PDT
System.out.println(timeZone2.getDisplayName(false, TimeZone.SHORT));//PST
System.out.println(timeZone2.getID());//America/Los_Angeles
TimeZone timeZone3 = TimeZone.getTimeZone("GMT+00:10");
System.out.println(timeZone3.getDisplayName(true, TimeZone.LONG));//GMT+00:10
System.out.println(timeZone3.getDisplayName(false, TimeZone.LONG));//GMT+00:10
System.out.println(timeZone3.getDisplayName(true, TimeZone.SHORT));//GMT+00:10
System.out.println(timeZone3.getDisplayName(false, TimeZone.SHORT));//GMT+00:10
System.out.println(timeZone3.getID());//GMT+00:10
}
Calendar
Calendar类是一个抽象类,它为特定瞬间与一组诸如YEAR、MONTH、DAY_OF_MONTH、HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间1970 年 1 月 1 日的00:00:00.000,格里高利历)的偏移量。由于Calendar是抽象类,它有多个子类,例如GregorianCalendar(格里高利历或称公历)、JapaneseImperialCalendar(JDK7.0增加)。与其他语言环境敏感类一样,Calendar 提供了一个类方法getInstance,以获得此类型的一个通用的对象。Calendar的getInstance方法返回一个Calendar子类的对象,其日历字段已由当前日期和时间初始化:
public static Calendar getInstance()
返回的 Calendar 基于当前时间,使用了默认时区和默认语言环境。
public static Calendar getInstance(Locale aLocale)
返回的 Calendar 基于当前时间,使用了默认时区和给定的语言环境。
public static Calendar getInstance(TimeZone zone)
返回的 Calendar 基于当前时间,使用了给定时区和默认语言环境。
public static Calendar getInstance(TimeZone zone,Locale aLocale)
返回的 Calendar 基于当前时间,使用了给定的时区和给定的语言环境。
Calendar使用两个参数定义了特定于语言环境的7天制星期,可以在sun.util.resources包中的CalendarData_<locale>.class (on Oracle JVM)查看:
星期的第一天(firstDayOfWeek):例如,在美国,这一天是SUNDAY,而在法国,这一天是MONDAY,在Calendar类中,中国默认也是SUNDAY。
一年或一个月中第一个星期所需的最少天数(minimalDaysInFirstWeek):范围是1-7。这些数字取自构造Calendar时的Locale(参考java.util.Calendar#setWeekCountData和sun.util.resources.cldr.zh.CalendarData_zh_Hans_CN)。还可以通过为其设置值的方法来显式地指定它们。
可以通过调用set方法来设置日历字段值。在需要计算时间值(距历元所经过的毫秒)或日历字段值之前,不会解释Calendar中的所有字段值设置。调用get、getTimeInMillis、getTime、add 和roll涉及此类计算。
Calendar有两种解释日历字段的模式,即lenient和non-lenient。当Calendar处于 lenient 模式时,它可接受比它所生成的日历字段范围更大范围内的值。当Calendar重新计算日历字段值,以便由get()返回这些值时,所有日历字段都被标准化。例如,lenient模式下的GregorianCalendar将MONTH == JANUARY、DAY_OF_MONTH == 32解释为February 1。 当Calendar处于non-lenient模式时,如果其日历字段中存在任何不一致性,它都会抛出一个异常。例如,GregorianCalendar总是在1与月份的长度之间生成DAY_OF_MONTH值。如果已经设置了任何超出范围的字段值,那么在计算时间或日历字段值时,处于non-lenient模式下的GregorianCalendar会抛出一个异常。public void setLenient(boolean lenient)可以设置宽松性。
GregorianCalendar
GregorianCalendar是Calendar最重要的一个子类,提供了世界上大多数国家/地区使用的标准日历系统。 GregorianCalendar是一种混合日历,同时支持儒略历和格里高利历系统。setGregorianChange(Date date)设置GregorianCalendar的更改日期。这是发生从儒略历日期切换到格里高利历日期的点。默认时间是1582 年 10 月 15 日(格里高利历)。在此之前,日期是按照儒略历计算的。 要得到纯粹的儒略历日历,可将更改setGregorianChange日期设置为Date(Long.MAX_VALUE)。要得到一个纯粹的格里高利历日历,可将更改setGregorianChange日期设置为Date(Long.MIN_VALUE)。 历史上,在那些首先采用格里高利历的国家/地区中,1582 年 10 月 4 日(儒略历)之后就是 1582 年 10 月 15 日(格里高利历)。此日历正确地模拟了这些变化。在开始格里高利历之前,GregorianCalendar实现的是儒略历。格里高利历和儒略历之间的唯一区别就是闰年规则。儒略历指定每 4 年就为闰年,而格里高利历则忽略不能被400整除的世纪年。
WEEK_OF_YEAR 字段值的范围从1 到 53。一年的第一个星期始于getFirstDayOfWeek()的最早7天,至少包含该年的getMinimalDaysInFirstWeek()天。这取决于getMinimalDaysInFirstWeek()、getFirstDayOfWeek()的值以及1 月 1 日是星期几。一年的第一个星期和下一年的第一个星期之间的各个星期按顺序从2到52或53(根据需要)进行编号。 例如,1998 年 1 月 1 日是星期四。如果getFirstDayOfWeek()为MONDAY,并且getMinimalDaysInFirstWeek()为4(这些值反映了ISO 8601和很多国家/地区标准),则1998 年的第一个星期开始于1997 年 12 月 29 日,结束于1998 年 1 月 4 日。但是,如果getFirstDayOfWeek()为SUNDAY,那么1998年的第一个星期开始于1998 年 1 月 4 日,结束于1998 年 1 月 10 日;1998年头三天是1997 年第53个星期的一部分。
WEEK_OF_MONTH 字段值的范围从0到6。一个月的第一个星期(WEEK_OF_MONTH = 1 的日期)是该月至少连续 getMinimalDaysInFirstWeek() 天中的最早日期,结束于 getFirstDayOfWeek() 的前一天。与一年的第一个星期不同,一个月的第一个星期可能短于7天,也不必从getFirstDayOfWeek()这一天开始,并且不包括前一个月的日期。在第一个星期之前该月日期的WEEK_OF_MONTH为0。 例如,如果getFirstDayOfWeek() 为SUNDAY,getMinimalDaysInFirstWeek()为4,那么1998 年 1 月的第一个星期是从1 月 4 日星期日到1 月 10 日星期六。这些天的 WEEK_OF_MONTH 为1。1 月 1 日星期四到1 月 3 日星期六的WEEK_OF_MONTH为0。如果getMinimalDaysInFirstWeek() 变为3,则1 月 1 日到1 月 3 日的 WEEK_OF_MONTH 为 1。
set(f, value)
将日历字段f更改为value。此外,它设置了一个内部成员变量,以指示日历字段f已经被更改。尽管日历字段f是立即更改的,但是直到下次调用get()、getTime()、getTimeInMillis()、add() 或 roll()时才会重新计算日历的时间值(以毫秒为单位)。因此,多次调用set()不会触发多次不必要的计算。使用set()更改日历字段的结果是,其他日历字段也可能发生更改,这取决于日历字段、日历字段值和日历系统。
示例:假定GregorianCalendar最初被设置为1999 年 8 月 31 日。调用set(Calendar.MONTH, Calendar.SEPTEMBER)将该日期设置为 1999 年 9 月 31 日。这是1999 年 10 月 1 日的一个暂时内部表示。此时月份按道理应该是10月,但是,在调用getTime()之前调用set(Calendar.DAY_OF_MONTH, 30) 会将该日期设置为1999 年 9 月 30 日,因为在调用set()之后没有发生重新计算。
add(f, delta)
将delta添加到f字段中。这等同于调用set(f, get(f) + delta)。与set()不同,add()强迫日历系统立即重新计算日历的毫秒数和所有字段。add()有两个规则:
1、调用后f字段的值减去调用前f字段的值等于delta,字段f字段值超出其范围时,下一个更大的字段会递增或递减,并将字段值调整回其范围内。
2、如果期望某一个更小的字段是不变的,但是让它等于以前的值是不可能的,因为在当前字段发生更改之后,或者在出现其他约束之后,比如时区偏移量发生更改,更小字段的最大值和最小值也在发生更改,然后它的值被调整为尽量接近于所期望的值。更小的字段表示一个更小的时间单元,例如HOUR是一个比DAY_OF_MONTH更小的字段。对于不期望是不变字段的更小字段,无需进行任何调整。日历系统例如格里高利历等会自行确定期望不变的有哪些字段。
示例:假定GregorianCalendar最初被设置为1999 年 8 月 31 日。调用add(Calendar.MONTH, 13) 将日历设置为2000 年 9 月 30 日。Add 规则1 MONTH字段设置为September,因为向August添加13个月得出的就是下一年的September。因为在GregorianCalendar 中,DAY_OF_MONTH不可能是9 月 31 日,所以add 规则2将DAY_OF_MONTH设置为30,即最可能的值。尽管DAY_OF_WEEK是一个更小的字段,但不能根据规则2调整DAY_OF_WEEK,因为在GregorianCalendar中的月份发生变化时,该值也需要发生变化。这个例子可以理解为,月份往后增加13个月后的月份最后一天。
roll(f, delta)
将delta添加到f字段中,这等同于调用add(f, delta),但不更改更大的字段。更大的字段表示一个更大的时间单元。DAY_OF_MONTH 是一个比HOUR大的字段。
add和roll的区别
原来设置为1999 年 8 月 31 日的GregorianCalendar 。现在调用roll(Calendar.MONTH, 8) 将该日历设置为1999 年 4 月 30 日。如果使用GregorianCalendar,则4月份的DAY_OF_MONTH字段不可能为 31。将DAY_OF_MONTH设置为最可能接近的值30。YEAR字段保持为值1999,因为它是一个比MONTH 更大的字段,所以不能改变。
原来设置为1999 年 6 月 6日星期日的GregorianCalendar 。现在调用roll(Calendar.WEEK_OF_MONTH, -1) 将该日历设置为1999 年 6 月 1 日星期二,而调用add(Calendar.WEEK_OF_MONTH, -1) 则将日历设置为1999 年 5 月 30 日星期日。这是因为上升和下降规则施加了其他的约束:WEEK_OF_MONTH改变时MONTH必须不变。所得日期必定在6 月 1日星期二和6 月 5 日星期六之间。DAY_OF_WEEK(在改变WEEK_OF_MONTH时它是一个不变量)被设置为Tuesday,是最接近Sunday的可能值(其中星期日是一个星期的第一天)。
public GregorianCalendar()
在具有默认语言环境的默认时区内使用当前时间构造一个默认的GregorianCalendar。
public GregorianCalendar(TimeZone zone)
在具有默认语言环境的给定时区内构造一个基于当前时间的GregorianCalendar。
public GregorianCalendar(Locale aLocale)
在具有给定语言环境的默认时区内构造一个基于当前时间的GregorianCalendar。
public GregorianCalendar(TimeZone zone,Locale aLocale)
在具有给定语言环境的给定时区内构造一个基于当前时间的GregorianCalendar。
public GregorianCalendar(int year,int month, int dayOfMonth)
在具有默认语言环境的默认时区内构造一个带有给定日期设置的GregorianCalendar。
public GregorianCalendar(int year,int month,int dayOfMonth,int hourOfDay, int minute)
为具有默认语言环境的默认时区构造一个具有给定日期和时间设置的GregorianCalendar。
public GregorianCalendar(int year, int month,int dayOfMonth,int hourOfDay,int minute,int second)
为具有默认语言环境的默认时区构造一个具有给定日期和时间设置的GregorianCalendar。
例如:
private static String getDayOfWeek(int i) {
switch (i) {
case Calendar.SUNDAY:
return "星期日";
case Calendar.MONDAY:
return "星期一";
case Calendar.TUESDAY:
return "星期二";
case Calendar.WEDNESDAY:
return "星期三";
case Calendar.THURSDAY:
return "星期四";
case Calendar.FRIDAY:
return "星期五";
case Calendar.SATURDAY:
return "星期六";
default:
return "";
}
}
public static void main(String[] args) {
//当前时间,设置GregorianCalendar的环境为中国所在时区和中国的语言环境
GregorianCalendar gregorianCalendar = new GregorianCalendar(TimeZone.getTimeZone("Asia/Shanghai"), Locale.CHINA);
//获取每周第一天和每年第一周的最少天数
System.out.println("第一周的最少天数:" + gregorianCalendar.getMinimalDaysInFirstWeek());
System.out.println("每周第一天是:" + getDayOfWeek(gregorianCalendar.getFirstDayOfWeek()));
//即使设置了中国语言环境,这里获取到的每周第一天还是星期日,因此需要手动设置
gregorianCalendar.setFirstDayOfWeek(Calendar.MONDAY);
System.out.println("每周第一天是:" + getDayOfWeek(gregorianCalendar.getFirstDayOfWeek()));
//打印各个字段
System.out.println("公元前或者公元后:" + (gregorianCalendar.get(Calendar.ERA) == GregorianCalendar.BC ? "公元前" :
(gregorianCalendar.get(Calendar.ERA) == GregorianCalendar.AD ? "公元" : "")));
System.out.println("年:" + gregorianCalendar.get(Calendar.YEAR));
//月份从0-11
System.out.println("月:" + (gregorianCalendar.get(Calendar.MONTH) + 1));
System.out.println("当前年中第几周:" + gregorianCalendar.get(Calendar.WEEK_OF_YEAR));
System.out.println("当前年中第几天:" + gregorianCalendar.get(Calendar.DAY_OF_YEAR));
System.out.println("当前月中第几周:" + gregorianCalendar.get(Calendar.WEEK_OF_MONTH));
//1到7总是对应于DAY_OF_WEEK_IN_MONTH 1;8 到 14总是对应于DAY_OF_WEEK_IN_MONTH 2,依此类推
//负数是从末尾开始计算,固定一周为7天
System.out.println("当前月中第几周(固定):" + gregorianCalendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
System.out.println("当前月中第几天:" + gregorianCalendar.get(Calendar.DATE));
System.out.println("当前月中第几天:" + gregorianCalendar.get(Calendar.DAY_OF_MONTH));
System.out.println("星期:" + getDayOfWeek(gregorianCalendar.get(Calendar.DAY_OF_WEEK)));
System.out.println("上午或者下午:" + (gregorianCalendar.get(Calendar.AM_PM) == GregorianCalendar.AM ? "上午" :
(gregorianCalendar.get(Calendar.AM_PM) == GregorianCalendar.PM ? "下午" : "")));
//上午或下午的小时。HOUR用于12小时制时钟 (0 - 11)。中午和午夜用0表示,不用12表示。
System.out.println("小时:" + gregorianCalendar.get(Calendar.HOUR));
//一天中的小时。HOUR_OF_DAY用于24小时制时钟。
System.out.println("小时:" + gregorianCalendar.get(Calendar.HOUR_OF_DAY));
System.out.println("分钟:" + gregorianCalendar.get(Calendar.MINUTE));
System.out.println("秒钟:" + gregorianCalendar.get(Calendar.SECOND));
System.out.println("毫秒:" + gregorianCalendar.get(Calendar.MILLISECOND));
//以毫秒为单位指示距GMT的大致偏移量
System.out.println("时区偏移量:" + gregorianCalendar.get(Calendar.ZONE_OFFSET));
//以毫秒为单位指示夏令时的偏移量。
System.out.println("夏令时偏移量:" + gregorianCalendar.get(Calendar.DST_OFFSET));
}
输出:
第一周的最少天数:1
每周第一天是:星期日
每周第一天是:星期一
公元前或者公元后:公元
年:2018
月:9
当前年中第几周:38
当前年中第几天:261
当前月中第几周:4
当前月中第几周(固定):3
当前月中第几天:18
当前月中第几天:18
星期:星期二
上午或者下午:下午
小时:2
小时:14
分钟:34
秒钟:54
毫秒:473
时区偏移量:28800000
夏令时偏移量:0
夏令时
public static void main(String[] args) throws Exception {
//澳大利亚悉尼时区是UTC+10
//夏令时开始于当地时间每年10月份第一个星期日的2点 2018-10-07 02:00
//结束于当地时间每年4月份第一个星期日的3点 2019-04-07 03:00
//UTC时间2018-10-06 16:00:00开始夏令时
//UTC时间2019-04-06 16:00:00结束夏令时
TimeZone sydney = TimeZone.getTimeZone("Australia/Sydney");
TimeZone beijing = TimeZone.getTimeZone("Asia/Shanghai");
TimeZone UTC = TimeZone.getTimeZone("UTC");
SimpleDateFormat sydneyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sydneyFormat.setTimeZone(sydney);
SimpleDateFormat beijingFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
beijingFormat.setTimeZone(beijing);
GregorianCalendar gregorianCalendar1 = new GregorianCalendar(UTC);
gregorianCalendar1.set(Calendar.YEAR, 2018);
gregorianCalendar1.set(Calendar.MONTH, Calendar.OCTOBER);
gregorianCalendar1.set(Calendar.DAY_OF_MONTH, 6);
gregorianCalendar1.set(Calendar.HOUR_OF_DAY, 15);
gregorianCalendar1.set(Calendar.MINUTE, 59);
gregorianCalendar1.set(Calendar.SECOND, 59);
gregorianCalendar1.set(Calendar.MILLISECOND, 999);
GregorianCalendar gregorianCalendar2 = new GregorianCalendar(UTC);
gregorianCalendar2.set(Calendar.YEAR, 2018);
gregorianCalendar2.set(Calendar.MONTH, Calendar.OCTOBER);
gregorianCalendar2.set(Calendar.DAY_OF_MONTH, 6);
gregorianCalendar2.set(Calendar.HOUR_OF_DAY, 16);
gregorianCalendar2.set(Calendar.MINUTE, 0);
gregorianCalendar2.set(Calendar.SECOND, 0);
gregorianCalendar2.set(Calendar.MILLISECOND, 0);
System.out.println("===========================================================");
System.out.println("悉尼:" + sydneyFormat.format(gregorianCalendar1.getTime())
+ " 对应北京时间:" + beijingFormat.format(gregorianCalendar1.getTime()));
System.out.println("夏令时开始");
System.out.println("悉尼:" + sydneyFormat.format(gregorianCalendar2.getTime())
+ " 对应北京时间:" + beijingFormat.format(gregorianCalendar2.getTime()));
System.out.println("===========================================================");
GregorianCalendar gregorianCalendar3 = new GregorianCalendar(UTC);
gregorianCalendar3.set(Calendar.YEAR, 2019);
gregorianCalendar3.set(Calendar.MONTH, Calendar.APRIL);
gregorianCalendar3.set(Calendar.DAY_OF_MONTH, 6);
gregorianCalendar3.set(Calendar.HOUR_OF_DAY, 15);
gregorianCalendar3.set(Calendar.MINUTE, 59);
gregorianCalendar3.set(Calendar.SECOND, 59);
gregorianCalendar3.set(Calendar.MILLISECOND, 999);
GregorianCalendar gregorianCalendar4 = new GregorianCalendar(UTC);
gregorianCalendar4.set(Calendar.YEAR, 2019);
gregorianCalendar4.set(Calendar.MONTH, Calendar.APRIL);
gregorianCalendar4.set(Calendar.DAY_OF_MONTH, 6);
gregorianCalendar4.set(Calendar.HOUR_OF_DAY, 16);
gregorianCalendar4.set(Calendar.MINUTE, 0);
gregorianCalendar4.set(Calendar.SECOND, 0);
gregorianCalendar4.set(Calendar.MILLISECOND, 0);
System.out.println("悉尼:" + sydneyFormat.format(gregorianCalendar3.getTime())
+ " 对应北京时间:" + beijingFormat.format(gregorianCalendar3.getTime()));
System.out.println("夏令时结束");
System.out.println("悉尼:" + sydneyFormat.format(gregorianCalendar4.getTime())
+ " 对应北京时间:" + beijingFormat.format(gregorianCalendar4.getTime()));
System.out.println("===========================================================");
}
输出:
===========================================================
悉尼:2018-10-07 01:59:59 对应北京时间:2018-10-06 23:59:59
夏令时开始
悉尼:2018-10-07 03:00:00 对应北京时间:2018-10-07 00:00:00
===========================================================
悉尼:2019-04-07 02:59:59 对应北京时间:2019-04-06 23:59:59
夏令时结束
悉尼:2019-04-07 02:00:00 对应北京时间:2019-04-07 00:00:00
===========================================================