分享 Ruby 及 Java 8 中时间日期处理

perky123 · 2018年06月30日 · 2800 次阅读

最近在学习 Java,并且公司一部分服务已经在从 Ruby 向 Java 做迁移,自己对 Java 及 Ruby 的时间相关的格式化及一些用法做了一些总结。

1. 获取当前的日期

Java

LocalDate 用于表示当天日期,与 java.util.Date 不同,只有日期,不包含时间。

LocalDate now = LocalDate.now();
System.out.println(now);

输出:

2018-06-20

Ruby

[8] pry(main)> Date.today
=> Fri, 29 Jun 2018
[9] pry(main)> Date.today.to_s
=> "2018-06-29"

2. 获取年/月/日信息

Java

LocalDate 提供了年/月/日的快捷方法,不需要再以来 java.util.Calendar 类了。

LocalDate now = LocalDate.now();
int year = now.getYear();
int monthValue = now.getMonthValue();
int dayOfMonth = now.getDayOfMonth();
System.out.printf("year = %d, month = %d, day = %d", year, monthValue, dayOfMonth);

输出:

year = 2018, month = 6, day = 29

Ruby

[1] pry(main)> Date.today.year
=> 2018
[2] pry(main)> Date.today.month
=> 6
[3] pry(main)> Date.today.day
=> 29

3. 创建新的日期对象

Java

可以调用另一个有用的工厂方法 LocalDate.of() 创建任意日期,该方法需要传入年、月、日做参数,返回对应的 LocalDate 实例。

LocalDate date = LocalDate.of(2018, 06, 29);
System.out.println(date);

输出:

2018-06-29

Ruby

[5] pry(main)> Date.new(2018, 06, 29)
=> Fri, 29 Jun 2018

4. 判断两个日期是否相等

Java

Java 8 提供了 equals 方法来判断是否是否相等,LocalDate 重载了 equals 方法

LocalDate now = LocalDate.now();
LocalDate date = LocalDate.of(2018, 06, 29);
if (date.equals(now)) {
    System.out.println("同一天");
}

输出:

同一天

Ruby

[10] pry(main)> date = Date.new(2018, 06, 29)
=> Fri, 29 Jun 2018
[11] pry(main)> date == Date.today
=> true

5. 检查特殊日期

Java

Java 8 中有一个类来检查每月账单/生日/结婚纪念日这些周期性事件=>MonthDay 类,这个类组合了月份和日,去掉了年,与此类似还有一个 YearMonth 类。

LocalDate now = LocalDate.now();
LocalDate dateOfBirth = LocalDate.of(2018, 06, 29);
MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth());
MonthDay currentMonthDay = MonthDay.from(now);
if (currentMonthDay.equals(birthday)) {
    System.out.println("Happy Birthday");
} else {
    System.out.println("Sorry, today is not your birthday");
}

输出:

Happy Birthday

Ruby

[20] pry(main)> Date.today
=> Fri, 29 Jun 2018
[21] pry(main)> now = Date.today
=> Fri, 29 Jun 2018
[22] pry(main)> date_of_birth = Date.new(2018, 06, 29)
=> Fri, 29 Jun 2018
[23] pry(main)> birth_month, birth_day = date_of_birth.month, date_of_birth.day
=> [6, 29]
[24] pry(main)> current_month, current_day = now.month, now.day
=> [6, 29]
[25] pry(main)> if (current_month == birth_month && birth_day == current_day)
[25] pry(main)*   p "Happy Birthday"
[25] pry(main)* else
[25] pry(main)*   p "Sorry, today is not your birthday"
[25] pry(main)* end
"Happy Birthday"
=> "Happy Birthday"

6. 获取当前时间

Java

Java 8 中获取时间使用的是 LocalTime 类,可以调用静态工厂方法 now() 来获取当前时间,默认格式是“hh:mm:ss:nnn”

LocalTime localTime = LocalTime.now();
System.out.println(localTime);

输出:

13:35:56.155

Ruby

[36] pry(main)> Time.now.strftime("%H:%M:%S.%L")
=> "17:20:36.447"

7. 在现有时间上增加小时/增加一周/增加一年/减少一年

Java

通过增加小时、分、秒来计算将来的时间很常见。Java 8 除了不变类型和线程安全的好处之外,还提供了更好的 plusHours() 方法替换 add(),并且是兼容的。注意,这些方法返回一个全新的 LocalTime 实例,由于其不可变性,返回后一定要用变量赋值。

LocalTime localTime = LocalTime.now();
System.out.println(localTime);
LocalTime localTime1 = localTime.plusHours(2);//增加2小时
System.out.println(localTime1);

输出:

17:28:22.812
19:28:22.812

增加一周,LocalDate 的日期不包含时间信息,它的 plus() 方法用来增加天/周/月

LocalDate now = LocalDate.now();
LocalDate plusDate = now.plus(1, ChronoUnit.WEEKS);
System.out.println(now);
System.out.println(plusDate);

输出:

2018-06-29
2018-07-06
LocalDate now = LocalDate.now();
LocalDate minusDate = now.minus(1, ChronoUnit.YEARS);
LocalDate plusDate1 = now.plus(1, ChronoUnit.YEARS);
System.out.println(minusDate);
System.out.println(plusDate1);

输出:

2017-06-29
2019-06-29

Ruby

增加 2 小时/增加一周/增加一年/减少一年

[41] pry(main)> DateTime.now
=> Fri, 29 Jun 2018 17:57:25 +0800
[42] pry(main)> DateTime.now + 2.hours
=> Fri, 29 Jun 2018 19:57:31 +0800
[44] pry(main)> DateTime.now + 1.weeks
=> Fri, 06 Jul 2018 17:57:48 +0800
[45] pry(main)> DateTime.now + 1.year
=> Sat, 29 Jun 2019 17:57:53 +0800
[46] pry(main)> DateTime.now - 1.year
=> Thu, 29 Jun 2017 17:58:00 +0800

8. 获取时间戳

Java

//获取毫秒数
Long milliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
//获取秒数
Long second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));

输出:

1530267881396
1530267881

Ruby

[49] pry(main)> DateTime.now.strftime('%s')
=> "1530267924"
[50] pry(main)> DateTime.now.strftime('%Q')
=> "1530267928882"

9. 日期转为字符串

Java

LocalDateTime arrivalDate  = LocalDateTime.now();
try {
    DateTimeFormatter format = DateTimeFormatter.ofPattern("MMMdd yyyy  hh:mm a");
    String landing = arrivalDate.format(format);
    System.out.printf("Arriving at :  %s %n", landing);
}catch (DateTimeException ex) {
    System.out.printf("%s can't be formatted!%n", arrivalDate);
    ex.printStackTrace();
}

输出:

Arriving at :  六月30 2018  09:12 下午

Ruby

[51] pry(main)> DateTime.now.to_s
=> "2018-06-30T21:15:41+08:00"

另外在 Rails 可以在 config/initializers 定义 time_formats.rb 文件,然后在整个 Rails 项目中都可以使用类似 DateTime.now.to_s(:ll) 这样的写法来格式化输出时间

# time_formats.rb

Time::DATE_FORMATS[:od] = "%Y-%m-%d"
Time::DATE_FORMATS[:odb] = "%Y-%m-%d"
Time::DATE_FORMATS[:ss] = "%Y-%m-%d %k:%M "
Time::DATE_FORMATS[:ll] = "%Y-%m-%d %H:%M:%S"
Time::DATE_FORMATS[:lll] = "%Y-%m-%d %H:%M:%S.%L"
Time::DATE_FORMATS[:ot] = "%H:%M "
Time::DATE_FORMATS[:lt] = "%H:%M:%S "
Time::DATE_FORMATS[:month_and_year] = "%B %Y"
Time::DATE_FORMATS[:short_ordinal] = lambda { |time| time.strftime("%B #{time.day.ordinalize}") }
Time::DATE_FORMATS[:md] = "%m-%d"
Time::DATE_FORMATS[:ww] = "%Y-%m-%d (%A)" # day with week day
Time::DATE_FORMATS[:year_month] = "%Y-%m"
Time::DATE_FORMATS[:ms] = lambda{|time| time.to_datetime.strftime "%Q" }

Java 8 日期时间 API 的重点

通过这些例子,你肯定已经掌握了 Java 8 日期时间 API 的新知识点。现在来回顾一下这个优雅 API 的使用要点:

  • 提供了 javax.time.ZoneId 获取时区。
  • 提供了 LocalDate 和 LocalTime 类。
  • Java 8 的所有日期和时间 API 都是不可变类并且线程安全,而现有的 Date 和 Calendar API 中的 java.util.Date 和 SimpleDateFormat 是非线程安全的。
  • 主包是 java.time, 包含了表示日期、时间、时间间隔的一些类。里面有两个子包 java.time.format 用于格式化,java.time.temporal 用于更底层的操作。
  • 时区代表了地球上某个区域内普遍使用的标准时间。每个时区都有一个代号,格式通常由区域/城市构成(Asia/Tokyo),在加上与格林威治或 UTC 的时差。例如:东京的时差是 +09:00。
  • OffsetDateTime 类实际上组合了 LocalDateTime 类和 ZoneOffset 类。用来表示包含和格林威治或 UTC 时差的完整日期(年、月、日)和时间(时、分、秒、纳秒)信息。
  • DateTimeFormatter 类用来格式化和解析时间。与 SimpleDateFormat 不同,这个类不可变并且线程安全,需要时可以给静态常量赋值。DateTimeFormatter 类提供了大量的内置格式化工具,同时也允许你自定义。在转换方面也提供了 parse() 将字符串解析成日期,如果解析出错会抛出 DateTimeParseException。DateTimeFormatter 类同时还有 format() 用来格式化日期,如果出错会抛出 DateTimeException 异常。
  • 再补充一点,日期格式“MMM d yyyy”和“MMM dd yyyy”有一些微妙的不同,第一个格式可以解析“Jan 2 2014”和“Jan 14 2014”,而第二个在解析“Jan 2 2014”就会抛异常,因为第二个格式里要求日必须是两位的。如果想修正,你必须在日期只有个位数时在前面补零,就是说“Jan 2 2014”应该写成“Jan 02 2014”。

关于 java 的部分参考了:http://www.54tianzhisheng.cn/2018/06/20/java-8-date/

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号