Calendar、LocalDateTime介绍与基本使用

九、Calendar

1.引用

import java.util.Calendar;

2.作用

①Calendar类提供了一些方法用于转换特定的时刻和Calendar字段(如YEAR、MONTH、DAY_OF_MONTH等)。
②Calendar类还提供了一些操作Calendar字段的方法,例如”getFirstDayOfWeek()”。
③简而言之,Calendar是专门用来操作年月日时分秒的类
④Calendar始于JDK1.1(原文)。

3.实例化

1)当前时间
Calendar中的两个构造方法均为protected,因此只能使用静态方法getInstance()来创建Calendar对象。

Calendar calendar = Calendar.getInstance();        //初始化一个表示当前时刻的Calendar对象

getInstance()共有四个重载方法,用来初始化不同时区、不同地区的Calendar对象。

public static Calendar getInstance();                                //默认时区、默认地区
public static Calendar getInstance(TimeZone zone);                   //指定时区、默认地区
public static Calendar getInstance(Locale aLocale);                  //默认时区、指定地区
public static Calendar getInstance(TimeZone zone, Locale aLocale);   //指定时区、指定地区

注意:getInstance()方法最终会将时间设为System.currentTimeMillis()。
2)指定时间
在调用getInstance()创建Calendar对象之后,再调用下述set方法可将Calendar置为指定时间。

public final void setTime(Date date);          //根据Date类来设定
public void setTimeInMillis(long millis);      //根据时间戳来设定
public void set(int field, int value);         //设置指定Calendar字段的值,field为Calendar中定义的各个常量,例:Calendar.MONTH
//注意:calendar.set(Calendar.MONTH, 11); 其中11并不是11月,而是12月,可使用Calendar.DECEMBER代替
public final void set(int year, int month, int date, int hourOfDay, int minute, int second);    //设定年月日时分秒

4.转换

1)Calendar转Date

Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();

2)Date转Calendar

Calendar calendar = Calendar.getInstance();
Date date = new Date();
calendar.setTime(date);     

3)Calendar转String

先将Calendar转为Date类,再使用SimpleDateFormat类将Date转String。

5.使用

Calendar常用的几个方法。
1)get()
获取指定字段的值,返回值为int

public int get(int field);
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);               //month = 2,并不是指2月,而是Calendar类中3月对应的int是2
int day = calendar.get(Calendar.DATE);
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);     //dayOfWeek = 3,并不是指周三,而是周二
上述结果为:year = 2020,month = 2,day = 10,dayOfWeek = 3

2)getDisplayName()
获取指定字段的值,返回值为String

public String getDisplayName(int field, int style, Locale locale);      //根据style和locale展示某个field的值
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MONTH, 11);               //11 也可用 Calendar.DECEMBER 来代替,更加直观
String shortMon = calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.US);
String narrowMon = calendar.getDisplayName(Calendar.MONTH, Calendar.NARROW_FORMAT, Locale.US);
String longMon = calendar.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.US);
上述结果为:shortMon = Dec,narrowMon = D,longMon = December

注意:
①一般只使用Calendar.SHORTCalendar.LONG两种style。Calendar.NARROW_FORMAT只显示首字母,存在重复无法识别的情况。
②get()获取到的是数字值,getDisplayName()获取到的是String值。
③Year、Day这类数据只有int一种表示方法,因此使用getDisplayName()会返回null。
3)getDisplayNames()
获取某个字段的所有展示值返回值为Map<String, Integer>

public String getDisplayNames(int field, int style, Locale locale);     //根据style和locale展示某个字段的所有展示
Calendar calendar = Calendar.getInstance();
Map<String, Integer> chinaNames = calendar.getDisplayNames(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.CHINA);
Map<String, Integer> usNames = calendar.getDisplayNames(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.US);
上述结果为:
chinaNames = {星期二=3, 星期六=7, 星期三=4, 星期四=5, 星期五=6, 星期日=1, 星期一=2}
usNames = {Monday=2, Thursday=5, Friday=6, Sunday=1, Wednesday=4, Tuesday=3, Saturday=7}

4)add()

abstract public void add(int field, int amount);      //增、减某个字段的值,amount正为增,负为减
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, -7);
calendar.add(Calendar.DATE, 10);

注意:若当前为3月,amount为-5,add()之后月份为9月;日期类似,也可倒退到1之前。
5)比较

public boolean before(Object when);                  //是否早于
public boolean after(Object when);                   //是否迟于
public int compareTo(Calendar anotherCalendar);      //比较。0 = 相等;小于0 = 早于;大于0 = 迟于

十、LocalDateTime

1.为什么使用

1)LocalDateTime是Java8推出的Date类的升级版,若条件允许,推荐使用LocalDateTime。
2)Date体系混乱且复杂,存在两个java.util.Datejava.sql.Date类,还需配套的Calendar、TimeZone、Locale类等。
3)Date若不格式化,打印出的日期可读性差,而SimpleDateFormat格式化Date的操作是线程不安全的。
4)LocalDateTime简单,学习简单、使用简单。

2.引用

import java.time.LocalDateTime;

3.实例化

构造方法访问权限为private,不可用。使用静态方法now()来实例化。

LocalDateTime now = LocalDateTime.now();        //实例化一个表示当前时间的LocalDateTime类

或者使用静态方法of()直接指定年月日时分秒来实例化。

LocalDateTime time1 = LocalDateTime.of(2020, 3, 10, 18, 22, 34, 633);    //指定 年月日、时分秒、纳秒
LocalDateTime time2 = LocalDateTime.of(2020, 3, 10, 18, 22, 34);         //指定 年月日、时分秒
LocalDateTime time3 = LocalDateTime.of(2020, 3, 10, 18, 22);             //指定 年月日、时分

注意:
 1)月的范围是1到12,也可用枚举类java.time.Month来代替。
 2)日的范围是1到31,时的范围是0到23,分、秒的范围是0到59。
 3)若使用of()时超出上述范围,编译会报错。

4.转换

1)LocalDateTime转String
利用toString()方法进行转换,其默认格式为:yyyy-MM-ddTHH:mm:ss.SSS

LocalDateTime now = LocalDateTime.now();
System.out.println(now);        //输出 2020-03-10T15:34:48.926

或者使用LocalDateTime的format()方法转换为自定义格式的String。通过DateTimeFormatter来指定需要的String格式。

LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String time = now.format(formatter);

注:ISO 8601标准格式转换DateTimeFormatter.ofPattern(“yyyy-MM-dd’T’HH:mm:ss’Z’”)
DateTimeFormatter有15种内置格式(以下为部分):

DateTimeFormatter.BASIC_ISO_DATE               20200310
DateTimeFormatter.ISO_LOCAL_DATE_TIME          2020-03-10T18:30:34
DateTimeFormatter.ISO_LOCAL_DATE               2020-03-10
DateTimeFormatter.ISO_DATE_TIME                2020-03-10T18:30:34
DateTimeFormatter.ISO_ORDINAL_DATE             2020-070

2)LocalDateTime转指定时区的String

LocalDateTime now = LocalDateTime.now(ZoneId.of("UTC"));        //实例化时指定时区
String time = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

或者

LocalDateTime now = LocalDateTime.now();
LocalDateTime utc = now.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
String time = utc.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

3)String转LocalDateTime
使用LocalDateTime.parse()进行解析,String中的时间格式必须与DateTimeFormatter的pattern匹配。

String time = "2020-03-10 11:11:11";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.parse(time, formatter);

4)Date转LocalDateTime
时间戳是所有系统通用的表示时间的方式,因此通过时间戳来转换Date和LocalDateTime。
具体使用LocalDateTime.ofInstant()进行转换(Java中将时间戳抽象为Instant类)。

Date date = new Date();
LocalDateTime time = LocalDateTime.ofInstant(date.toInstant(), ZoneId.of("Asia/Shanghai"));

:因为时间戳不带有任何地区信息,所以ofInstant()方法需要借助ZoneId类。
5)LocalDateTime转Date
借助Instant类使用Date.from()方法来转换。

LocalDateTime now = LocalDateTime.now();
Date date = Date.from(now.toInstant(ZoneOffset.of("+8")));

ZoneOffset.of(“+8”)+8代表中国时区,其他时区可+/- N
6)LocalDateTime转Unix

long utc = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);          //转表示UTC的unix
long cst = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));     //转表示CST的unix

5.使用

LocalDateTime常用的几类方法。
1)获取某个字段值

LocalDateTime now = LocalDateTime.now();
int year = now.getYear();                       //年
Month month = now.getMonth();                   //月
int monthValue = now.getMonthValue();           //int类型的月
int day = now.getDayOfMonth();                  //日
DayOfWeek dayOfWeek = now.getDayOfWeek();       //星期几,dayOfWeek.getValue()获取int值,周一int值为1,周天为7
int hour = now.getHour();                       //时
int minute = now.getMinute();                   //分

2)加减
a.加减操作有三类方法,分别以plusminuswith开头;
b.三类方法入参都可正可负,意味着每类方法都可以单独实现加、减两个功能,但是根据约定plus用来加,minus用来减;
c.minus实际调用了plus方法,而plus方法最终又调用了with方法;

LocalDateTime now = LocalDateTime.now();
LocalDateTime plusDays = now.plusDays(3);
LocalDateTime minusDays = now.minusDays(3);
LocalDateTime withDays = now.withDayOfMonth(3);

注意:三类方法并不改变自己身的值,而是返回一个修改过值得副本。 3)比较

LocalDateTime now = LocalDateTime.now();
LocalDateTime future = now.plusDays(3);
boolean after = now.isAfter(future);            //是否迟于
boolean before = now.isBefore(future);          //是否早于
boolean equal = now.isEqual(future);            //是否相等
int i = now.compareTo(future);                  //负为早于,正为迟于,0为相等

4)计算
利用java.time.Duration类来计算两个LocalDateTime之间的时间差。

LocalDateTime now = LocalDateTime.now();
LocalDateTime plusDays = now.plusDays(3);
Duration between = Duration.between(now, plusDays);
long days = between.toDays();         //正为plusDays迟于now几天,负为早于
long hours = between.toHours();
long minutes = between.toMinutes();