Java 日期和随机数

这一章节 我们主要学习 java.util 中的 Date 类、Calendar 类,Random 类以及 java.time 包中的 LocalTime 类。

java.util 和 java.time 包

ava.util 包提供了一些实用的方法和数据结构。比如日期类 Date,日历类 Calendar 以及随机数类 Random,同时包里还提供了 collection 框架,像堆栈 Stack、向量 Vector、位集合 Bitset 以及哈希表 Hashtable 等表示数据结构的类。而 java.time 包是 java8 新提供的包,里面对时间和日期提供了新的 api,弥补了 java.util 包对日期和时间操作的不足。

Date

Date 类表示时间和日期,里面封装了操作日期和时间的方法. Date类经常用来获取系统当前时间。

Date中当前未过时的构造方法:

构造方法 说明
Date() 构造一个Date对象并对其进行初始化以反映当前时间
Date(long date) 构造一个Date对象,并根据相对于GMT1970年1月1日 00:00:00 的毫秒数对其进行初始化

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.util.*;
public class DateDemo {
public static void main(String[] args) throws ClassNotFoundException {
String strDate, strTime = "";
Date objDate = new Date();
System.out.println("今天的日期是:" + objDate);
long time = objDate.getTime();
System.out.println("自 1970 年 1 月 1 日起以毫秒为单位的时间(GMT):" + time);
strDate = objDate.toString();
//提取 GMT 时间
strTime = strDate.substring(11,(strDate.length() - 4));
//按小时、分钟和秒提取时间
strTime = "时间:" + strTime.substring(0,8);
System.out.println(strTime);
}
}

温馨提示 Date 很多方法在JDK1.1开始就已经过时了.想要了解可以去官网查询

Calendar

在早期的JDK版本中,Date类附有两大功能:

  1. 允许用年、月、日、时、分、秒来解释日期
  2. 允许对表示日期的字符串进行格式化和句法分析

在JDK1.1中提供了类Calendar来完成第一种功能,类DateFormat来完成第二项功能。DateFormat是java.text包中的一个类。与Date类有所不同的是,DateFormat类可以接受用各种语言和不同习惯表示的日期字符串。

但是Calendar类是一个抽象类,它完成Date类与普通日期表示法之间的转换,而我们更多的是使用Calendar类的子类GregorianCalendar类。它实现了世界上普遍的公历系统。当然我们也可以继承Calendar类,然后自己定义实现日历的方法.

GregorianCalendar 构造方法:

构造方法 说明
GregorianCalendar 创建的对象中的相关值被设置成指定时区,缺省地点的当前时间,即程序运行时所处的时区、地点的当前时间
GregorianCalendar(TimeZone zone) 创建的对象中的相关值被设置成指定时区zone,缺省地点的当前时间
GregorianCalendar(Locale aLocale) 创建的对象中的相关值被设置成缺省的时区,指定地点aLocale的当前时间
GregorianCalendar(TimeZone zone,Locale aLocale) year - 创建的对象中的相关值被设置成指定时区,指定地点的当前时间

TimeZone是java.util包中的一个类,其中封装了有关时区的信息。每一个时区对应一组ID。类TimeZone提供了一些方法完成时区与对应ID两者之间的转换。

例如:

1
2
3
4
// 太平洋时区的ID为PST
TimeZone tz0 = TimeZone.getTimeZone("PST");
// getDefault() 可以获取主机所处时区对象
TimeZone tz1 = TimeZone.getDefault();

Locale只是一种机制,它用来标识一个特定的地理、政治或文化区域获取一个Locale对象的构造方法:

1
2
3
4
5
6
7
// 调用 Locale 类的构造方法  
Locale 10 = new Locale(String language);
Locale 11 = new Locale(String language,String country);
Locale 12 = new Locale(String language, String country, String variant);

// 调用 Locale 类中定义的常量
Locale 11 = Locale.CHINA;

一个简单的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import java.util.*;
import java.text.*;

public class CalendarDemo
{
public static void main(String[] args)
{

// 得到日期格式对象
// Date date = fmt.parse(strDateMake);

System.out.println("完整显示日期时间:");
// 字符串转换日期格式
DateFormat fdate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str =fdate.format(new Date());
System.out.println(str);

// 创建 Calendar 对象
Calendar calendar = Calendar.getInstance();
// 初始化 Calendar 对象,但并不必要,除非需要重置时间
calendar.setTime(new Date());

// 显示年份
System.out.println("年: " + calendar.get(Calendar.YEAR));

// 显示月份 (从 0 开始,实际显示要加一)
System.out.println("月: " + calendar.get(Calendar.MONTH));

// 当前分钟数
System.out.println("分钟: " + calendar.get(Calendar.MINUTE));

// 今年的第 N 天
System.out.println("今年的第 " + calendar.get(Calendar.DAY_OF_YEAR) + "天");

// 本月第 N 天
System.out.println("本月的第 " + calendar.get(Calendar.DAY_OF_MONTH) + "天");

// 3 小时以后
calendar.add(Calendar.HOUR_OF_DAY, 3);
System.out.println("三小时以后的时间: " + calendar.getTime());
// 格式化显示
str = (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS")).format(calendar.getTime());
System.out.println(str);

// 重置 Calendar 显示当前时间
calendar.setTime(new Date());
str = (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS")).format(calendar.getTime());
System.out.println(str);

// 创建一个 Calendar 用于比较时间
Calendar calendarNew = Calendar.getInstance();

// 设定为 5 小时以前,后者大,显示 -1
calendarNew.add(Calendar.HOUR, -5);
System.out.println("时间比较:" + calendarNew.compareTo(calendar));

// 设定 7 小时以后,前者大,显示 1
calendarNew.add(Calendar.HOUR, +7);
System.out.println("时间比较:" + calendarNew.compareTo(calendar));

// 退回 2 小时,时间相同,显示 0
calendarNew.add(Calendar.HOUR, -2);

// calendarNew 创建时间点
System.out.println((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS")).format(calendarNew.getTime()));
// calendar 创建时间点
System.out.println((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS")).format(calendar.getTime()));
System.out.println("时间比较:" + calendarNew.compareTo(calendar));
}
}

其实 month 的含义与 Date 类相同,0 代表 1 月,11 代表 12 月。

有的人可能不明白最后一个的输出为什么有时是 0 ,有时是 1,在这里会涉及到 calendarNew 与 calendar 的创建时间点, calendarNew 经过增加和减少时间后恢复到原来的时间点,也就是最终比较的是谁先创建好,时间点靠后的大一些,而 calendarNew 创建的时间点只有可能是大于等于 calendar 的,需要根据实际的创建时间点进行比较。

java.time

因为 java8 之前的日期和时间 api 饱受诟病,比如线程安全问题,比如 Date 的月份是从 0 开始的!而 java.time 包中将月份封装成为了枚举类型。接下来来看看如何使用这个新的时间报

首先了解一下 LocalTime 类,LocalTime 类是一个不可变类(也就是用 final 修饰的类),和 String 类一样,所以它是线程安全的。除了 LocalTime 还有 LocalDate(日期)、LocalDateTime(日期和时间)等,他们的使用方式都差不多。下面来实际编写一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import java.time.*;
import java.time.temporal.ChronoUnit;

public class TimeDemo {
public static void main(String[] args) {
// 获得当前的日期和时间
LocalDateTime currentTime = LocalDateTime.now();
System.out.println("current date and time: " + currentTime);

// 输出当前时间的本地值(本时区)
LocalDate date1 = currentTime.toLocalDate();
System.out.println("local date: " + date1);

Month month = currentTime.getMonth();
int day = currentTime.getDayOfMonth();
int seconds = currentTime.getSecond();

// 由当前时间对象获得各个字段,输出结果
System.out.println("month: " + month +"day: " + day +"seconds: " + seconds);

// 由当前时间附带月份和年再输出
LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
System.out.println("date 2: " + date2);

// 输出 2016 年圣诞节的日期
LocalDate date3 = LocalDate.of(2016, Month.DECEMBER, 25);
System.out.println("date 3: " + date3);

// 输出新闻联播的开始时间
LocalTime date4 = LocalTime.of(19, 00);
System.out.println("date 4: " + date4);

// 转化为字符串,再输出
LocalTime date5 = LocalTime.parse("20:15:30");
System.out.println("date 5: " + date5);

// 将字符串代表的时区信息转化
ZonedDateTime date6 = ZonedDateTime.parse("2016-04-20T19:22:15+01:30[Europe/Paris]");
System.out.println("date1: " + date6);

// 设定地区 ID 为亚洲的加尔各答(位于印度),并输出
ZoneId id = ZoneId.of("Asia/Kolkata");
System.out.println("ZoneId: " + id);

// 获得系统默认的当前地区并输出
ZoneId currentZone = ZoneId.systemDefault();
System.out.println("CurrentZone: " + currentZone);

// 获得当前的日期并输出
LocalDate today = LocalDate.now();
System.out.println("Current date: " + today);

// 在当前日期的基础上增加两周时间再输出
LocalDate nextWeek = today.plus(2, ChronoUnit.WEEKS);
System.out.println("two weeks after now: " + nextWeek);

// 在当前日期的基础上增加 6 个月的时间再输出
LocalDate nextMonth = today.plus(6, ChronoUnit.MONTHS);
System.out.println("6 months after now: " + nextMonth);

// 在当前日期的基础上增加 5 年的时间再输出
LocalDate nextYear = today.plus(5, ChronoUnit.YEARS);
System.out.println("5 years after now: " + nextYear);

// 在当前日期的基础上增加 20 年的时间再输出(一个 Decade 为 10 年)
LocalDate nextDecade = today.plus(2, ChronoUnit.DECADES);
System.out.println("20 years after now: " + nextDecade);
}
}

Random

java实用工具类库中的类 java.util.Random 提供了昌盛各种类型随机的方法。它可以产生int、long、float、double 以及Gaussian等类型的随机数。这也是它与java.lang.Math 中的方法Random() 最大的不同之处,后者只产生double型的随机数

构造方法 说明
Random() 产生一个随机数需要基数,这里将系统时间作为seed
Random(long seed) 使用单个long种子创建一个新的随机数生成器

普通方法原型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//该方法是设定基值 seed
public synchronized void setSeed(long seed)

//该方法是产生一个整型随机数
public int nextInt()

//该方法是产生一个 long 型随机数
public long nextLong()

//该方法是产生一个 Float 型随机数
public float nextFloat()

//该方法是产生一个 Double 型随机数
public double nextDouble()

//该方法是产生一个 double 型的 Gaussian 随机数
public synchronized double nextGaussian()

/*
synchronized 是 Java 语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码
*/

大家可以验证和尝试一下引入上面所讲的所有类,调用一下里面的各种方法

参考链接

在线文档-jdk-zh