「Java深层系列」让我们一起完全吃透时间和日期相关的API指南

SimpleDateFormat df = new SimpleDateFormat(ALTERNATIVE_ISO8601_DATE_FORMAT, Locale.US);

df.setTimeZone(new SimpleTimeZone(0, “GMT”));

return df;

}

RFC 822

=======

STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES

其中ARPA网络其实就是互联网的前身。

有些地方会用RFC 822里的时间格式,格式如下

date-time = [ day “,” ] date time ; dd mm yy

; hh:mm:ss zzz

第二个相当于现在格式

==========

“EEE, dd MMM yyyy HH:mm:ss z”

有些头设置采用该格式。

joda中实现如下

// RFC 822 Date Format

private static final String RFC822_DATE_FORMAT = “EEE, dd MMM yyyy HH:mm:ss z”;

private static DateFormat getRfc822DateFormat() {

SimpleDateFormat rfc822DateFormat =

new SimpleDateFormat(RFC822_DATE_FORMAT, Locale.US);

rfc822DateFormat.setTimeZone(new SimpleTimeZone(0, “GMT”));

return rfc822DateFormat;

}

创建SimpleDateFormat的Locale.US可以决定格式字符串某些字符的代替用哪个语言,比如EEE等。

SimpleDateFormat df1=new SimpleDateFormat(“GGGG yyyy/MMMM/dd HH:mm:ss EEE aaa zzzz”,Locale.CHINA);

SimpleDateFormat df2=new SimpleDateFormat(“GGGG yyyy/MMMM/dd HH:mm:ss EEE aaa zzzz”,Locale.US);

//公元 2016/三月/27 23:32:10 星期日 下午 中国标准时间

//AD 2016/March/27 23:32:10 Sun PM China Standard Time

gregorian Calendar, julian Calendar:这是两种历法,我们一般用的通用的gregorian Calendar。

jdk1.8之前

========

主要的类有记录时间戳的Date,时间和日期进行转换的Calendar,用来格式化和解析时间字符串的DateFormat

java.util.Date

==============

使用前要注意时间表示的规则。

还有这个类有很多过期方法不推荐使用,很多已经被Calendar代替。

构造方法

====

这个类代表某个时刻的毫秒值,既然是毫秒值也就说需要有一个参考值。

在接受或返回年、月、日期、小时、分钟和秒值的所有类日期方法中,使用以下表示形式:

年份y由整数y-1900表示。一个月由0到11的整数表示;0是一月,1是二月,依此类推;因此,11月是12月。日期(月的某一天)通常由1到31之间的整数表示。小时由0到23之间的整数表示。因此,从午夜到凌晨1点的时间是0小时,从中午到下午1点的时间是12小时。一分钟通常由0到59之间的整数表示。第二个由0到61之间的整数表示;值60和61仅在闰秒内出现,甚至仅在实际正确跟踪闰秒的Java实现中出现。由于目前引入闰秒的方式,在同一分钟内出现两个闰秒的可能性极低,但本规范遵循ISO C的日期和时间约定。

当我们创建一个Date的时候获取的是哪一个毫秒值?

public Date() {

this(System.currentTimeMillis());

}

public Date(long date) {

fastTime = date;

}

System.currentTimeMillis()是本地方法,the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC。

这个可能会因为操作系统的时间而不准。有些操作系统不一定是用毫秒表示的。这个时间都是用的UTC时间,不和时区有关的,这个无关的意思是同一时刻每个时区下获得的值应该是一致的,可以简单用程序验证一下获取的时间表达内容。

long time = System.currentTimeMillis();

System.out.println(time=(time/1000));

System.out.println(“秒:”+ time%60);

System.out.println(time=(time/60));

System.out.println(“分钟:”+time%60);

System.out.println(time=(time/60));

System.out.println(“小时:”+time%24);

可以理解成和UTC的1970年1月1日零点的差值。而fastTime就是Date类保存这个时刻的变量。

成员变量

====

Date对象打印出来是本地时间,而构造方法是没有时区体现的。那么哪里体现了时区呢?

下面是Date的成员变量

gcal

====

获取的是以下的对象。其中并没有自定义字段。可以说只是一个gregorian(公历)时间工厂获取CalendarDate的子类。

jcal

====

在以下方法中用到

private static final BaseCalendar getCalendarSystem(BaseCalendar.Date cdate) {

if (jcal == null) {

return gcal;

}

if (cdate.getEra() != null) {

return jcal;

}

return gcal;

}

synchronized private static final BaseCalendar getJulianCalendar() {

if (jcal == null) {

jcal = (BaseCalendar) CalendarSystem.forName(“julian”);

}

return jcal;

}

当时间戳在以下情况下用儒略历,并且,在用到的时候会自动设置儒略历,所以在clone的时候也没有这个参数。所以这个可以忽略。

private static final BaseCalendar getCalendarSystem(int year) {

if (year >= 1582) {

return gcal;

}

return getJulianCalendar();

}

private static final BaseCalendar getCalendarSystem(long utc) {

// Quickly check if the time stamp given by `utc’ is the Epoch

// or later. If it’s before 1970, we convert the cutover to

// local time to compare.

if (utc >= 0

|| utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER

  • TimeZone.getDefaultRef().getOffset(utc)) {

return gcal;

}

return getJulianCalendar();

}

fastTime

========

保存了一个时间戳表示时刻。最重要的参数。创建Date就是对这个值的赋值。

cdate

=====

保存了时间相关内容,包括时区,语言等

public static final int FIELD_UNDEFINED = -2147483648;

public static final long TIME_UNDEFINED = -9223372036854775808L;

private Era era;

private int year;

private int month;

private int dayOfMonth;

private int dayOfWeek;

private boolean leapYear;

private int hours;

private int minutes;

private int seconds;

private int millis;

private long fraction;

private boolean normalized;

private TimeZone zoneinfo;

private int zoneOffset;

private int daylightSaving;

private boolean forceStandardTime;

private Locale locale;

defalutCenturyStart

===================

这个值可以忽略,在过期方法中用到。

@Deprecated

public static long parse(String s) {

… …

// Parse 2-digit years within the correct default century.

if (year < 100) {

synchronized (Date.class) {

if (defaultCenturyStart == 0) {

defaultCenturyStart = gcal.getCalendarDate().getYear() - 80;

}

}

year += (defaultCenturyStart / 100) * 100;

if (year < defaultCenturyStart) year += 100;

}

… …

}

serialVersionUID

================

验证版本一致性的UID

wtb

===

保存toString格式化用到的值

ttb

===

保存toString 格式化用到的值

主要方法

====

「Java深层系列」让我们一起完全吃透时间和日期相关的API指南

java.util.Calendar

==================

主要也是其中保存的毫秒值time字段,下面是我们常用的方法,用了默认的时区和区域语言:

public static Calendar getInstance() {

return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));

}

国内环境默认GregorianCalendar,但是TH-th用的BuddhistCalendar等

一些坑:

set(int,int,int,int,int,int)方法

==============================

方法不能设置毫秒值,所以当用getInstance后即使用设置相同的值,最后毫秒值也是不一致的。所以如果有需要,将MILLISECOND清零。

set,add,get,roll

================

set方法不会马上计算时间,指是修改了对应的成员变量,只有get()、getTime()、getTimeInMillis()、add() 或 roll()的时候才会做调整

//2000-8-31

Calendar cal1 = Calendar.getInstance();

cal1.set(2000, 7, 31, 0, 0 , 0);

//应该是 2000-9-31,也就是 2000-10-1

cal1.set(Calendar.MONTH, Calendar.SEPTEMBER);

//如果 Calendar 转化到 2000-10-1,那么现在的结果就该是 2000-10-30

cal1.set(Calendar.DAY_OF_MONTH, 30);

//输出的是2000-9-30,说明 Calendar 不是马上就刷新其内部的记录

System.out.println(cal1.getTime());

也就是说多次设置的时候如果中间有需要调整的时间,但是实际是不会做调整的。所以尽量将无法确定的设置之后不要再进行其他调整,防止最后实际值与正常值不准。

add方法会马上做时间修改

=============

roll与add类似,但是roll不会修改更大的字段的值。

java.text.SimpleDateFormat

==========================

创建设置pattern字符串,可以表示的格式如下:

「Java深层系列」让我们一起完全吃透时间和日期相关的API指南

日期格式是不同步的。建议为每个线程创建独立的格式实例。如果多个线程同时访问一个格式,则它必须是外部同步的。

SimpleDateFormat 是线程不安全的类,其父类维护了一个Calendar,调用相关方法有可能会修改Calendar。一般不要定义为static变量,如果定义为 static,必须加锁,或者使用 DateUtils 工具类。 正例:注意线程安全,使用 DateUtils。

org.apache.commons.lang.time.DateUtils,也推荐如下处理:

private static final ThreadLocal df = new ThreadLocal() {

@Override

protected DateFormat initialValue() {

return new SimpleDateFormat(“yyyy-MM-dd”);

}

};

java.sql.Date/Time/Timestamp

============================

这几个类都继承了java.util.Date。

相当于将java.util.Date分开表示了。Date表示年月日等信息。Time表示时分秒等信息。Timestamp多维护了纳秒,可以表示纳秒。

如果是 JDK8 的应用,可以使用 Instant 代替 Date,LocalDateTime 代替 Calendar, DateTimeFormatter 代替SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe。

jdk1.8的时间类

==========

1.8增加了新的date-time包,遵循JSR310。核心代码主要放在java.time包下。默认的日历系统用的ISO-8601(基于格里高利历)。

java.time下主要内容包括:

java.time -主要包括,日期,时间,日期时间,时刻,期间,和时钟相关的类。

  • java.time.chrono -其他非ISO标准的日历系统可以用java.time.chrono,里面已经定义了一部分年表,你也可以自定义。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了

《Java中高级核心知识全面解析》

小米商场项目实战,别再担心面试没有实战项目:

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了

《Java中高级核心知识全面解析》

[外链图片转存中…(img-ddDXqDv0-1713518200775)]

小米商场项目实战,别再担心面试没有实战项目:

[外链图片转存中…(img-8P7b8hCB-1713518200777)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 26
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值