日期时间API 也是Java 8重要的更新之一,Java从一开始就缺少一致的日期和时间方法,Java 8 Date Time API是Java核心API的一个非常好的补充。
Java中现有的与日期和时间相关的类存在一些问题:
java.util和java.sql包中都有Date类。同样,格式化和解析类是在java.text包中定义的。java.util.Date同时包含日期和时间值,而java.sql.Date只包含日期值,把它放在java.sql包中是没有意义的。而且这两个类的名称相同,这本身就是一个非常糟糕的设计。java.text.DateFormat抽象类用于解析和格式化,通常使用SimpleDateFormat类解析和格式化。Date类都是可变的,所以它们不是线程安全的,这也是JavaDate和Calendar类最大的问题之一。Date类不提供国际化,不支持时区。虽然引入了java.util.Calendar和java.util.TimeZone,但是它们也存在上面的问题。在Date和Calendar类中定义的方法还有一些其他的问题,但是上面的问题清楚地表明,Java中需要一个健壮的日期时间API。这就是为什么 Joda Time 可以成为Java 日期时间高质量的替代品。
Java 8日期时间API是基于 JSR-310 规范实现的。目的是为了解决遗留日期时间实现中的所有缺陷。新的日期时间API的一些设计原则如下:
不变性:新的日期时间API中的所有类都是不可变的,适用于多线程环境。
关注点分离:新的日期时间API明确区分了人类可读的日期、时间和机器时间(Unix时间戳),它为Date、Time、DateTime、Timestamp、Timezone 等定义单独的类。
清晰性:所有的类中都清晰地定义了方法,并执行相同的操作。例如,要获取当前时间实例可以用now()方法,在所有这些类中都定义了format()和parse()方法,而不是为它们单独定义一个类。
所有类都使用工厂模式和策略模式来更好地操作。一旦您使用了其中一个类中的方法,使用其他类并不困难。
实用的操作:所有新的日期时间API类都常见的方法,比如加、减、格式化、解析、在日期/时间中获取单独的部分等等。
可扩展:新的日期时间API可以在ISO-8601日历系统上工作,但是我们也可以在其他非ISO日历上使用它。
Java8日期时间API由以下包组成。
java.time:这是Java 8日期时间API的基本包。所有主要的基类都是这个包的一部分,例如LocalDate、LocalTime、LocalDateTime、Instant、Period、Duration等。所有这些类都是不可变的和线程安全的。大多数情况下,这些类足以处理常见的需求。java.time.chrono:这个包为非ISO日历系统定义了通用API。我们可以扩展AbstractChronology类来创建我们自己的日历系统。java.time.format:这个包包含用于格式化和解析日期时间对象的类。大多数时候我们不会直接使用它们,因为java.time包中的日期时间类已经提供了格式化和解析方法。java.time.temporal:这个包包含temporal对象,我们可以使用它来找出与日期/时间对象相关的特定日期或时间。例如,我们可以使用它们来查找一个月的第一天或最后一天。您可以很容易地识别这些方法,因为它们的格式总是withXXX。java.time.zone:这个包包含用于支持不同时区及其规则的类。下面通过一些日期时间API类的示例,来更好的了解Java 8日期时间API
LocalDate是一个不可变的日期类,它以yyyy-MM-dd的默认格式表示日期。可以使用now()方法来获取当前日期,还可以提供年、月和日期的输入参数来创建LocalDate实例。
这个类为now()提供了一个重载方法,在这里可以传递ZoneId来获取特定时区中的日期。这个类提供了与java.sql.Date相同的功能。
// 当前日期
LocalDate today = LocalDate.now();
System.out.println("当前日期=" + today);
// 通过提供年月日参数创建日期
LocalDate nowYear_1024 = LocalDate.of(2022, Month.OCTOBER, 24);
System.out.println("参数日期=" + nowYear_1024);
// 通过时区获取当前日期
LocalDate todayShanghai = LocalDate.now(ZoneId.of("Asia/Shanghai"));
System.out.println("当前日期(CTT)=" + todayShanghai);
// 从纪元日(1970-01-01)开始的第多少天
LocalDate dateFromBase = LocalDate.ofEpochDay(365);
System.out.println("1970-01-01的第365天= " + dateFromBase);
// 某年的第多少天
LocalDate hundredDay2022 = LocalDate.ofYearDay(2022, 100);
System.out.println("2022年的第100天=" + hundredDay2022);
运行之后结果如下:
当前日期=2022-10-26
特殊日期=2022-10-24
当前日期(CTT)=2022-10-26
1970-01-01的第365天= 1971-01-01
2022年的第100天=2022-04-10
LocalTime是一个不可变的时间类,它以HH:mm:ss.SSS的默认格式表示时间。与LocalDate一样,这个类提供了时区支持,并可以通过传递小时、分钟和秒作为输入参数来创建实例。
// 当前时间
LocalTime time = LocalTime.now();
System.out.println("当前时间=" + time);
// 通过提供时分秒参数创建日期
LocalTime specificTime = LocalTime.of(12, 20, 25, 40);
System.out.println("参数时间=" + specificTime);
// 通过时区获取当前时间
LocalTime timeShanghai = LocalTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("当前时间(CTT)=" + timeShanghai);
// 从纪元日开始的第多少秒
LocalTime specificSecondTime = LocalTime.ofSecondOfDay(100);
System.out.println("从纪元日开始的第100秒=" + specificSecondTime);
运行之后结果如下:
当前时间=15:39:18.948
参数时间=12:20:25.000000040
当前时间(CTT)=15:39:18.949
从0开始的第100秒=00:01:40
LocalDateTime是一个不可变的日期时间类,它以yyyy-MM-ddTHH:mm:ss.SSS的默认格式表示时间日期。它提供了一个工厂方法,该方法使用LocalDate和LocalTime作为参数创建LocalDateTime实例。
// 当前日期时间
LocalDateTime now = LocalDateTime.now();
System.out.println("当前日期时间=" + now);
// 通过提供LocalDate和LocalTime参数创建日期时间
now = LocalDateTime.of(LocalDate.now(), LocalTime.now());
System.out.println("当前日期时间=" + now);
// 通过提供年月日时分秒参数创建日期时间
LocalDateTime specificTime = LocalDateTime.of(2022, Month.OCTOBER, 24, 10, 24, 24);
System.out.println("参数日期时间=" + specificTime);
// 通过时区获取当前日期时间
LocalDateTime todayKolkata = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("当前日期时间(CTT)=" + todayKolkata);
// 从纪元日开始的第多少秒
LocalDateTime dateFromBase = LocalDateTime.ofEpochSecond(100, 0, ZoneOffset.UTC);
System.out.println("从纪元日开始的第100秒= " + dateFromBase);
运行之后结果如下:
当前日期时间=2022-10-26T15:51:59.070
当前日期时间=2022-10-26T15:51:59.071
参数日期时间=2022-10-24T10:24:24
当前日期时间(CTT)=2022-10-26T15:51:59.071
从纪元日开始的第100秒=1970-01-01T00:01:40
注意:以上例子通过输入参数创建实例时,如果输入了无效的参数name将会抛出java.time.DateTimeException
instant类用于处理机器可读的时间格式。instant类将日期时间存储在unix时间戳中。
// 当期时间戳
Instant timestamp = Instant.now();
System.out.println("当期时间戳= "+timestamp);
// 从纪元日开始的第多少毫秒
Instant specificTime = Instant.ofEpochMilli(timestamp.toEpochMilli());
System.out.println("从纪元日开始="+specificTime);
运行之后结果如下:
当期时间戳=2022-10-26T08:08:40.429Z
从纪元日开始=2022-10-26T08:08:40.429Z
大多数日期时间类都会提供各种实用方法,例如加/减天数、周数、月数等。还有一些其他实用方法可以使用时间调整器TemporalAdjuster调整日期,并计算两个日期之间的时间段。
LocalDate today = LocalDate.now();
//获取年份,判断年份是否是闰年
System.out.println("Year "+today.getYear()+" is Leap Year? "+today.isLeapYear());
//比较两个时间
System.out.println("Today is before 01/01/2023? "+today.isBefore(LocalDate.of(2023,1,1)));
//通过LocalDate创建LocalDateTime
System.out.println("Current Time="+today.atTime(LocalTime.now()));
//加减操作
System.out.println("10 days after today will be "+today.plusDays(10));
System.out.println("3 weeks after today will be "+today.plusWeeks(3));
System.out.println("20 months after today will be "+today.plusMonths(20));
System.out.println("10 days before today will be "+today.minusDays(10));
System.out.println("3 weeks before today will be "+today.minusWeeks(3));
System.out.println("20 months before today will be "+today.minusMonths(20));
//时间调整器调整时间
System.out.println("First date of this month= "+today.with(TemporalAdjusters.firstDayOfMonth()));
LocalDate lastDayOfYear = today.with(TemporalAdjusters.lastDayOfYear());
System.out.println("Last date of this year= "+lastDayOfYear);
Period period = today.until(lastDayOfYear);
System.out.println("Period Format= "+period);
System.out.println("Months remaining in the year= "+period.getMonths());
运行之后结果如下:
Year 2022 is Leap Year? false
Today is before 01/01/2023? true
Current Time=2022-10-26T16:25:04.740
10 days after today will be 2022-11-05
3 weeks after today will be 2022-11-16
20 months after today will be 2024-06-26
10 days before today will be 2022-10-16
3 weeks before today will be 2022-10-05
20 months before today will be 2021-02-26
First date of this month= 2022-10-01
Last date of this year= 2022-12-31
Period Format= P2M5D
Months remaining in the year= 2
经常用到的操作有:将日期时间格式化为不同格式String,解析String以获得日期时间对象。
// 格式化
LocalDate date = LocalDate.now();
// 默认格式
System.out.println("Default format of LocalDate=" + date);
// 自定义格式
System.out.println(date.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE));
LocalDateTime dateTime = LocalDateTime.now();
// 默认格式
System.out.println("Default format of LocalDateTime=" + dateTime);
// 自定义格式
System.out.println(dateTime.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒")));
System.out.println(dateTime.format(DateTimeFormatter.BASIC_ISO_DATE));
Instant timestamp = Instant.now();
// 默认格式
System.out.println("Default format of Instant=" + timestamp);
// 解析
LocalDateTime dt = LocalDateTime.parse("2022年10月24日10时24分24秒",
DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒"));
System.out.println("Default format after parsing = " + dt);
运行之后结果如下:
Default format of LocalDate=2022-10-26
2022年10月26日
20221026
Default format of LocalDateTime=2022-10-26T16:37:51.300
2022年10月26日16时37分51秒
20221026
Default format of Instant=2022-10-26T08:37:51.301Z
Default format after parsing = 2022-10-24T10:24:24
遗留日期/时间类几乎在所有应用程序中都使用,因此必须有向下兼容。这就是为什么我们可以通过一些实用方法将遗留类转换为新类,反之亦然。
//Date转Instant
Instant timestamp = new Date().toInstant();
//Instant转LocalDateTime
LocalDateTime date = LocalDateTime.ofInstant(timestamp,
ZoneId.of(ZoneId.SHORT_IDS.get("CTT")));
System.out.println("Date = " + date);
//Calendar转Instant
Instant time = Calendar.getInstance().toInstant();
System.out.println(time);
//TimeZone转ZoneId
ZoneId defaultZone = TimeZone.getDefault().toZoneId();
System.out.println(defaultZone);
//ZonedDateTime from specific Calendar
ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();
System.out.println(gregorianCalendarDateTime);
//Date API to Legacy classes
Date dt = Date.from(Instant.now());
System.out.println(dt);
TimeZone tz = TimeZone.getTimeZone(defaultZone);
System.out.println(tz);
GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime);
System.out.println(gc);
运行之后结果如下:
Date = 2022-10-26T16:47:38.329
2022-10-26T08:47:38.429Z
Asia/Shanghai
2022-10-26T16:47:38.455+08:00[Asia/Shanghai]
Wed Oct 26 16:47:38 CST 2022
sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null]
java.util.GregorianCalendar[time=1666774058455,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2022,MONTH=9,WEEK_OF_YEAR=43,WEEK_OF_MONTH=4,DAY_OF_MONTH=26,DAY_OF_YEAR=299,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=47,SECOND=38,MILLISECOND=455,ZONE_OFFSET=28800000,DST_OFFSET=0]
可以看到,遗留的TimeZone和GregorianCalendar类toString()方法过于冗长,对用户不友好。
原文出处链接:https://www.ssymon.com/archives/java-8-date-time-api
万水千山总是情,点赞再走行不行。
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.
Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur
在Java中,可以像这样从一个字符串创建一个IO流:Readerr=newStringReader("mytext");我希望能够在Ruby中做同样的事情,这样我就可以获取一个字符串并将其视为一个IO流。 最佳答案 r=StringIO.new("mytext")和here'sthedocumentation. 关于java-Java的StringReader的Ruby等价物是什么?,我们在StackOverflow上找到一个类似的问题: https://st