Java之时间戳、Date(日期)、Calendar(日历)、时间转换和Date格式化

概念

时间原点概念

所有的数据类型,无论是整数,布尔,浮点数还是字符串,最后都需要以数字的形式表现出来。
日期类型也不例外,换句话说,一个日期,比如2020年10月1日,在计算机里,会用一个数字来代替。
那么最特殊的一个数字,就是零. 零这个数字,就代表Java中的时间原点,其对应的日期是1970年1月1日 8点0分0秒 。 (为什么是8点,因为中国的太平洋时区是UTC-8,刚好和格林威治时间差8个小时)
为什么对应1970年呢? 因为1969年发布了第一个 UNIX 版本,综合考虑,当时就把1970年当做了时间原点。所有的日期,都是以为这个0点为基准,每过一毫秒,就+1。

时间戳

简单讲,时间戳就是从1970-01-01开始所经过的秒数,什么时候获取时间戳,就是到那个时间点所经历的毫秒数。

说明:时间戳在Java中是13位,应该是代表的毫秒数,PHP和Python中是10位,应该是代表的秒数。

时区(TimeZone)和地区(Locale)

时区:这个名称有点不准确,其实应该叫“时间体系和偏移量”。
时间体系有很多种,古时中国人喜欢用皇帝名+登基时间来表示时间,这也是一种时间体系。现在比较常用的时间体系是GMT和UTC。GMT也就是格林威治时间,也叫格林尼治时间,从1970-01-01 00:00:00开始计算。UTC是在GMT基础上设计的,两者误差很小,作为凡人可以忽略。如果是要求很高的军工行业,则请查阅其他资料吧。

地区:所属地区。在中国一个星期的第一天是星期一,在西方第一天是星期日,这个小细节不注意可能会导致计算星期的时候出问题。

一、时间戳

System.out.println(new Date().getTime());
System.out.println(System.currentTimeMillis());

输出结果:

1578971073649
1578971073649

二、Date

1、创建一个当前时间的Date对象

Date date = new Date();
System.out.println("timestamp: "+date.getTime());
System.out.println("Date: "+new Date(date.getTime()));

输出结果:

timestamp: 1578970061366
Date: Tue Jan 14 10:47:41 CST 2020

2、创建一个我们指定的时间的Date对象:

使用带参数的构造方法Date(int year, int month, int day) ,可以构造指定日期的Date类对象,Date类中年份的参数应该是实际需要代表的年份减去1900,实际需要代表的月份减去1以后的值。

Date date1 = new Date(2020-1900,6-1,12);
String date1Str = TimeUtil.msToDate(date1.getTime());
System.out.println(date1Str);

输出结果:

2020-06-12 00:00:00

三、Calendar(日历)

(1)获取Calendar实例的四种方式

1.getInstance():使用默认的时区、默认的位置创建实例
2.getInstance(TimeZone zone):使用指定的时区、默认的位置创建实例
3.getInstance(Locale aLocale):使用默认的时区、指定的位置创建实例
4.getInstance(TimeZone zone,Locale aLocale)使用指定的时区、指定的位置创建实例

Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance(Locale.CHINA);
Calendar c3 = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
Calendar c4 = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"), Locale.CHINA);

(2)

add/set/roll方法区别

1.add方法:按照指定的时间单位向前/向后推移,会计算得到实际值
2.set方法:设置指定的时间单位,会计算得到实际值
3.roll方法:按照指定的时间单位向前/向后推移,不修改较大的时间单位,只会修改指定的时间单位

roll(int,int)和roll(int,boolean)的区别

1.roll(int,int):支持向前/向后推移多个时间单元
2.roll(int,boolean):向前/向后推移一个时间单元

set方法的四种不同参数形式的区别

1.set(int filed,int value):在指定时间单位设值
2.set(int year,int month,int day):给年、月、日时间单位设值
3.set(int year,int month,int day,int hourOfDay,int minute):给年、月、日、时、分单位设值
4.set(int year,int month,int day,int hourOfDay,int minute,int second):给年、月、日、时、分、秒单位设值

before/after方法区别

1.before:时间做比较,是否在该时间之前
2.after:时间做比较,是否在该时间之后

Calendar的一个例子:

Calendar calendar = Calendar.getInstance();
System.out.println("time: "+calendar.getTime());
System.out.println("long_time: "+calendar.getTimeInMillis());
System.out.println("TimeZone: "+calendar.getTimeZone());
System.out.println("year:"+calendar.get(Calendar.YEAR));
System.out.println("month:"+calendar.get(Calendar.MONTH)+1);
System.out.println("date of month: "+calendar.get(Calendar.DATE));
System.out.println("hour of day: "+calendar.get(Calendar.HOUR_OF_DAY));
System.out.println("hour: "+calendar.get(Calendar.HOUR));
System.out.println("minute: "+calendar.get(Calendar.MINUTE));
System.out.println("second:"+calendar.get(Calendar.SECOND));
System.out.println("day of week: "+(calendar.get(Calendar.DAY_OF_WEEK)-1));
System.out.println("====================整体设置值==========================");
calendar.set(2011,9-1,11,13,12,15);
System.out.println("整体设置后的时间: "+calendar.getTime());
System.out.println("====================分别设置============================");
calendar.set(Calendar.YEAR,2015);
calendar.set(Calendar.MONTH,7-1);
calendar.set(Calendar.DATE,1);
calendar.set(Calendar.HOUR_OF_DAY,9);
calendar.set(Calendar.MINUTE,10);
calendar.set(Calendar.SECOND,11);
System.out.println("单独设置后的时间: "+calendar.getTime());
System.out.println("====================单独运算============================");
calendar.add(Calendar.YEAR, 1);//年
calendar.add(Calendar.MONTH, 1);//月
calendar.add(Calendar.DATE, 1);//日
calendar.add(Calendar.HOUR_OF_DAY, -1);//时
calendar.add(Calendar.MINUTE, 1);//分
calendar.add(Calendar.SECOND, 1);//秒
System.out.println("运算之后的时间: "+calendar.getTime());
System.out.println("====================单独运算roll============================");
calendar.roll(Calendar.DAY_OF_MONTH, -3);//日
System.out.println("Roll之后的时间: "+calendar.getTime());
System.out.println("====================before&&after==========================");
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c2.set(Calendar.DAY_OF_MONTH,15);
System.out.println("c2晚于(大于)当前时间: "+c2.after(c1));
System.out.println("c2早于(小于)当前时间: "+c2.before(c1));

运行结果:

time: Tue Jan 14 14:33:25 CST 2020
long_time: 1578983605839
TimeZone: sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null]
year:2020
month:01
date of month: 14
hour of day: 14
hour: 2
minute: 33
second:25
day of week: 2
====================整体设置值==========================
整体设置后的时间: Sun Sep 11 13:12:15 CST 2011
====================分别设置============================
单独设置后的时间: Wed Jul 01 09:10:11 CST 2015
====================单独运算============================
运算之后的时间: Tue Aug 02 08:11:12 CST 2016
====================单独运算roll============================
Roll之后的时间: Tue Aug 30 08:11:12 CST 2016
====================before&&after==========================
c2晚于(大于)当前时间: true
c2早于(小于)当前时间: false

四、时间格式化转换和输出

(1)日期转字符串

例子:Tue Jan 14 11:14:03 CST 2020 转成 2020-01-14 11:14:03

Date date = new Date();
System.out.println("Date: "+date);
System.out.println("直接格式化date对象:"+TimeUtil.dateToDateStr(date));

输出结果:

Date: Tue Jan 14 11:14:03 CST 2020
直接格式化date对象:2020-01-14 11:14:03

(2)时间戳转日期格式的字符串

例子:15789716433662020-01-14 11:14:03

String curTime = TimeUtil.msToDate(System.currentTimeMillis(),"yyyy-MM-dd HH:mm:ss");
System.out.println("24小时制: "+curTime);
String curTime1 = TimeUtil.msToDate(System.currentTimeMillis(),"yyyy-MM-dd hh:mm:ss");
System.out.println("12小时制: "+curTime1);
String curTime2 = TimeUtil.msToDate(System.currentTimeMillis(),"yyyy/MM/dd HH:mm:ss");
System.out.println("另外一种格式1: "+curTime2);
String curTime3 = TimeUtil.msToDate(System.currentTimeMillis(),"MM/dd/yyyy HH:mm:ss");
System.out.println("另外一种格式2: "+curTime3);
String curTime4 = TimeUtil.msToDate(System.currentTimeMillis(),"HH:mm:ss");
System.out.println("只要时分秒: "+curTime4);
String curTime5 = TimeUtil.msToDate(System.currentTimeMillis(),"HH");
System.out.println("只要时: "+curTime5);
String curTime6 = TimeUtil.msToDate(System.currentTimeMillis(),"MM");
System.out.println("只要月: "+curTime6);

输出结果:

24小时制: 2020-01-14 11:14:03
12小时制: 2020-01-14 11:14:03
另外一种格式1: 2020/01/14 11:14:03
另外一种格式2: 01/14/2020 11:14:03
只要时分秒: 11:14:03
只要时: 11
只要月: 01

(3)日期格式的字符串转时间戳

!注意:模式(yyyy/MM/dd HH:mm:ss)需要和字符串格式保持一致,如果不一样就会抛出解析异常ParseException

例子:2020-01-13 17:26:101578907570000

long timeStamp0 = TimeUtil.dateToMs("2020-01-13");
System.out.println("时间戳格式和format不一致:"+timeStamp0);
long timeStamp1 = TimeUtil.dateToMs("2020-01-13 17:26:10");
System.out.println("时间戳和format一致:"+timeStamp1);
long timeStamp2 = TimeUtil.dateToMs("2020-01-13 17:26:10","yyyy-MM-dd hh:mm:ss");
System.out.println("时间戳和format在小时制上不一致:"+timeStamp2);
long timeStamp3 = TimeUtil.dateToMs("2020-01-13 17:26:10","yyyy-MM-dd HH:mm:ss");
System.out.println("时间戳和format在包括小时制在内都一致:"+timeStamp3);
long timeStamp4 = TimeUtil.dateToMs("2020/01/13 17:26:10","yyyy/MM/dd HH:mm:ss");
System.out.println("时间戳和另一种format在包括小时制在内都一致:"+timeStamp4);
long timeStamp5 = TimeUtil.dateToMs("17:26:10","HH:mm:ss");
System.out.println("时间戳和只有小时:"+timeStamp5);
long timeStamp6 = TimeUtil.dateToMs("01/13/2020 17:26:10","MM/dd/yyyy HH:mm:ss");
System.out.println("时间戳和另一种format在包括小时制在内都一致:"+timeStamp6);

输出结果:

时间戳格式和format不一致:0
时间戳和format一致:1578907570000
时间戳和format在小时制上不一致:1578907570000
时间戳和format在包括小时制在内都一致:1578907570000
时间戳和另一种format在包括小时制在内都一致:1578907570000
时间戳和只有小时:33970000
时间戳和另一种format在包括小时制在内都一致:1578907570000
注意格式化的时候指定的日期格式要严格按照yyyy-MM-dd HH:mm:ss.SSS这种(自考虑字母大小写和个数,连接符 - 和:自行改变),否则可能会出现一些错误。这里举几个:
  • yyyy必须小写,YYYY是基于周的,Java's DateTimeFormatter pattern "YYYY" gives you the week-based-year, (by default, ISO-8601 standard) the year of the Thursday of that week.具体看下方实例。
  • dd必须小写,DD是一年中的第几天,而不是月份中的第几天。
  • MM 和mm 一个代表月 一个代表分钟,这个不能乱写,否则你会发现你的月份变成了分钟数。
  • HH大写为24小时制
  • hh小写为12小时制

YYYY和yyyy的例子:

Date date2 = new Date(2019-1900,12-1,31);
Date date3 = new Date(2020-1900,1-1,1);
System.out.println("============================大写 YYYY==================================");
SimpleDateFormat formatYYYY = new SimpleDateFormat("YYYY/MM/dd", Locale.getDefault());
System.out.println("2019-12-31 转 YYYY/MM/dd 格式: " + formatYYYY.format(date2));
System.out.println("2020-01-01 转 YYYY/MM/dd 格式: " + formatYYYY.format(date3));
System.out.println("============================小写 yyyy==================================");
SimpleDateFormat formatyyyy = new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault());
System.out.println("2019-12-31 转 yyyy/MM/dd 格式: " + formatyyyy.format(date2));
System.out.println("2020-01-01 转 yyyy/MM/dd 格式: " + formatyyyy.format(date3));

输出结果:

============================大写 YYYY==================================
2019-12-31 转 YYYY/MM/dd 格式: 2020/12/31
2020-01-01 转 YYYY/MM/dd 格式: 2020/01/01
============================小写 yyyy==================================
2019-12-31 转 yyyy/MM/dd 格式: 2019/12/31
2020-01-01 转 yyyy/MM/dd 格式: 2020/01/01

2019-12-31号这一天,安周算年份已经属于2020年了,格式化之后就变成2020年,后面的月份日期不变。

最后附上用到的工具方法类:

public class TimeUtil {

    private static final String COMMON_FORMAT = "yyyy-MM-dd HH:mm:ss";

    /**
     * 将日期转换为标准的日期格式
     * @param date
     * @return
     */
    public static String dateToDateStr(Date date){
        SimpleDateFormat format = new SimpleDateFormat(COMMON_FORMAT, Locale.getDefault());
        return format.format(date);
    }

    /**
     * 将日期转换为标准的日期格式
     * @param date
     * @return
     */
    public static String dateToDateStr(Date date,String formatStr){
        SimpleDateFormat format = new SimpleDateFormat(formatStr, Locale.getDefault());
        return format.format(date);
    }

    /**
     * 将毫秒转换为标准日期格式
     *
     * @param _ms
     * @return
     */
    public static String msToDate(long _ms) {
        Date date = new Date(_ms);
        SimpleDateFormat format = new SimpleDateFormat(COMMON_FORMAT, Locale.getDefault());
        return format.format(date);
    }

    /**
     * 将毫秒(Java下时间戳)转换为日期格式,指定格式
     *
     * @param _ms
     * @param format
     * @return
     */
    public static String msToDate(long _ms, String format) {
        Date date = new Date(_ms);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format, Locale.getDefault());
        return simpleDateFormat.format(date);
    }

    /**
     * 标准格式化时间字符串转换为时间戳
     *
     * @param _data
     * @return
     */
    public static long dateToMs(String _data) {
        SimpleDateFormat format = new SimpleDateFormat(COMMON_FORMAT,Locale.getDefault());
        try {
            Date date = format.parse(_data);
            return date.getTime();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 格式化时间字符串转换为时间戳,指定要转化的时间字符串的格式
     *
     * @param pattern
     * @param _date
     * @return
     */
    public static long dateToMs(String _date,String pattern) {
        SimpleDateFormat format = new SimpleDateFormat(pattern,Locale.getDefault());
        try {
            Date date = format.parse(_date);
            return date.getTime();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 计算时间差
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static String dateDistance(Date startDate, Date endDate) {
        if (startDate == null || endDate == null) {
            return null;
        }
        long timeLong = endDate.getTime() - startDate.getTime();
        if (timeLong < 0) {
            timeLong = 0;
        }
        if (timeLong < 60 * 1000)
            return timeLong / 1000 + "秒前";
        else if (timeLong < 60 * 60 * 1000) {
            timeLong = timeLong / 1000 / 60;
            return timeLong + "分钟前";
        } else if (timeLong < 60 * 60 * 24 * 1000) {
            timeLong = timeLong / 60 / 60 / 1000;
            return timeLong + "小时前";
        } else if ((timeLong / 1000 / 60 / 60 / 24) < 7) {
            timeLong = timeLong / 1000 / 60 / 60 / 24;
            return timeLong + "天前";
        } else {
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd",Locale.getDefault());
            return formatter.format(startDate);
        }
    }
}

参考文章:
JAVA-日历Calendar小结
Java中YYYY-MM-DD要注意了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容