- 浏览: 2211694 次
- 性别:
- 来自: 北京
-
文章分类
- 全部博客 (682)
- 软件思想 (7)
- Lucene(修真篇) (17)
- Lucene(仙界篇) (20)
- Lucene(神界篇) (11)
- Solr (48)
- Hadoop (77)
- Spark (38)
- Hbase (26)
- Hive (19)
- Pig (25)
- ELK (64)
- Zookeeper (12)
- JAVA (119)
- Linux (59)
- 多线程 (8)
- Nutch (5)
- JAVA EE (21)
- Oracle (7)
- Python (32)
- Xml (5)
- Gson (1)
- Cygwin (1)
- JavaScript (4)
- MySQL (9)
- Lucene/Solr(转) (5)
- 缓存 (2)
- Github/Git (1)
- 开源爬虫 (1)
- Hadoop运维 (7)
- shell命令 (9)
- 生活感悟 (42)
- shell编程 (23)
- Scala (11)
- MongoDB (3)
- docker (2)
- Nodejs (3)
- Neo4j (5)
- storm (3)
- opencv (1)
最新评论
-
qindongliang1922:
粟谷_sugu 写道不太理解“分词字段存储docvalue是没 ...
浅谈Lucene中的DocValues -
粟谷_sugu:
不太理解“分词字段存储docvalue是没有意义的”,这句话, ...
浅谈Lucene中的DocValues -
yin_bp:
高性能elasticsearch ORM开发库使用文档http ...
为什么说Elasticsearch搜索是近实时的? -
hackWang:
请问博主,有用solr做电商的搜索项目?
Solr中Group和Facet的用法 -
章司nana:
遇到的问题同楼上 为什么会返回null
Lucene4.3开发之第八步之渡劫初期(八)
以前总觉得在Java里面处理各种日期转换很麻烦,虽然我也封装过一些工具包,但是总体感觉还是不够完美,也使用过一些开源的apachecommons里面的时间处理工具类感觉还是不够灵活和强大。
第一次与Joda-Time有一面之缘的时候,是在我使用ELK框架给公司做日志收集分析检索系统的时候,我发现使用jruby重写的logstash里面使用的时间处理工具类是joda-time,当时就对这个框架有点好奇,只不过没太注意,至于为什么会发现?相信搞过ELK的都知道logstash的时间处理比较独特,或者说不了解的情况下,可能会有点麻烦,当然logstash的作者,曾经开玩笑的说过一句话,新手遇到ELK里面的困难,第一肯定是栽在logstash里面,各种input,gork,filter,output插件总能有一款让你手无足措,额,有点扯远了,言归正传。如果说在logstash发现Joda-Time,并没引起我的兴趣,但是后来,我在hadoop,solr里面都发现有Joda-Time的踪影,而hadoop和solr恰恰当今最流行的开源框架,所以就抽空看了看这个精美的小工具,发现确实很不错,下面这篇文章是来自一位朋友的笔记:
先抛个问题:
求任何一年中的第 11 月的第一个星期二的日期,而这天必须是在这个月的第一个星期一之后。
大家思考下用你们各自擅长的语言实现,需要多少代码量?
答案在文末文章中,有例子。下面是正文:
任何企业应用程序都需要处理时间问题。应用程序需要知道当前的时间点和下一个时间点,有时它们还必须计算这两个时间点之间的路径。使用 JDK 完成这项任务将非常痛苦和繁琐。现在来看看 Joda Time,一个面向 Java™ 平台的易于使用的开源时间/日期库。正如您在本文中了解的那样,Joda-Time 轻松化解了处理日期和时间的痛苦和繁琐。
在编写企业应用程序时,我常常需要处理日期。并且在我的最新项目中 — 保险行业 — 纠正日期计算尤其重要。使用 java.util.Calendar 让我有些不安。如果您也曾使用这个类处理过日期/时间值,那么您就知道它使用起来有多麻烦。因此当我接触到 Joda-Time — 面向 Java 应用程序的日期/时间库的替代选择 — 我决定研究一下。其结果是:我很庆幸我这么做了。
Joda-Time 令时间和日期值变得易于管理、操作和理解。事实上,易于使用是 Joda 的主要设计目标。其他目标包括可扩展性、完整的特性集以及对多种日历系统的支持。并且 Joda 与 JDK 是百分之百可互操作的,因此您无需替换所有 Java 代码,只需要替换执行日期/时间计算的那部分代码。
Joda 大型项目
Joda 实际上是涵盖众多用于 Java 语言的替代 API 的大型项目,因此从技术上讲,使用 Joda 和 Joda-Time 名称表示相同的意思是一种误称。但在撰写本文之际,Joda-Time API 目前似乎是唯一处于活跃开发状态下的 Joda API。考虑到 Joda 大型项目的当前状态,我想将 Joda-Time 简称为 Joda 应该没什么问题。
本文将介绍并展示如何使用它。我将介绍以下主题:
日期/时间替代库简介
Joda 的关键概念
创建 Joda-Time 对象
以 Joda 的方式操作时间 style
以 Joda 的方式格式化时间
您可以 下载 演示这些概念的样例应用程序的源代码。
Joda 简介
为什么要使用 Joda?考虑创建一个用时间表示的某个随意的时刻 — 比如,2000 年 1 月 1 日 0 时 0 分。我如何创建一个用时间表示这个瞬间的 JDK 对象?使用 java.util.Date?事实上这是行不通的,因为自 JDK 1.1 之后的每个 Java 版本的 Javadoc 都声明应当使用 java.util.Calendar。Date 中不赞成使用的构造函数的数量严重限制了您创建此类对象的途径。
然而,Date 确实有一个构造函数,您可以用来创建用时间表示某个瞬间的对象(除 “现在” 以外)。该方法使用距离 1970 年 1 月 1 日子时格林威治标准时间(也称为 epoch)以来的毫秒数作为一个参数,对时区进行校正。考虑到 Y2K 对软件开发企业的重要性,您可能会认为我已经记住了这个值 — 但是我没有。Date 也不过如此。
那么 Calendar 又如何呢?我将使用下面的方式创建必需的实例:
Calendar calendar = Calendar.getInstance(); calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
使用 Joda,代码应该类似如下所示:
DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
这一行简单代码没有太大的区别。但是现在我将使问题稍微复杂化。假设我希望在这个日期上加上 90 天并输出结果。使用 JDK,我需要使用清单 1 中的代码:
清单 1. 以 JDK 的方式向某一个瞬间加上 90 天并输出结果
Calendar calendar = Calendar.getInstance(); calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0); SimpleDateFormat sdf = new SimpleDateFormat("E MM/dd/yyyy HH:mm:ss.SSS"); calendar.add(Calendar.DAY_OF_MONTH, 90); System.out.println(sdf.format(calendar.getTime()));
使用 Joda,代码如清单 2 所示:
清单 2. 以 Joda 的方式向某一个瞬间加上 90 天并输出结果
DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0); System.out.println(dateTime.plusDays(90).toString("E MM/dd/yyyy HH:mm:ss.SSS");
两者之间的差距拉大了(Joda 用了两行代码,JDK 则是 5 行代码)。
现在假设我希望输出这样一个日期:距离 Y2K 45 天之后的某天在下一个月的当前周的最后一天的日期。坦白地说,我甚至不想使用 Calendar 处理这个问题。使用 JDK 实在太痛苦了,即使是简单的日期计算,比如上面这个计算。正是多年前的这样一个时刻,我第一次领略到 Joda-Time 的强大。使用 Joda,用于计算的代码如清单 3 所示:
清单 3. 改用 Joda
DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0); System.out.println(dateTime.plusDays(45).plusMonths(1).dayOfWeek().withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS");
清单 3 的输出为:
Sun 03/19/2000 00:00:00.000
如果您正在寻找一种易于使用的方式替代 JDK 日期处理,那么您真的应该考虑 Joda。如果不是这样的话,那么继续痛苦地使用 Calendar 完成所有日期计算吧。当您做到这一点后,您完全可以做到使用几把剪刀修建草坪并使用一把旧牙刷清洗您的汽车。
Joda 和 JDK 互操作性
JDK Calendar 类缺乏可用性,这一点很快就能体会到,而 Joda 弥补了这一不足。Joda 的设计者还做出了一个决定,我认为这是它取得成功的构建:JDK 互操作性。Joda 的类能够生成(但是,正如您将看到的一样,有时会采用一种比较迂回的方式)java.util.Date 的实例(和 Calendar)。这使您能够保留现有的依赖 JDK 的代码,但是又能够使用 Joda 处理复杂的日期/时间计算。
例如,完成 清单3 中的计算后。我只需要做出如清单 4 所示的更改就可以返回到 JDK 中:
清单 4. 将 Joda 计算结果插入到 JDK 对象中
Calendar calendar = Calendar.getInstance(); DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0); System.out.println(dateTime.plusDays(45).plusMonths(1).dayOfWeek() .withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS"); calendar.setTime(dateTime.toDate());
就是这么简单。我完成了计算,但是可以继续在 JDK 对象中处理结果。这是 Joda 的一个非常棒的特性。
Joda 的关键日期/时间概念
Joda 使用以下概念,它们可以应用到任何日期/时间库:
不可变性(Immutability)
瞬间性(Instant)
局部性(Partial)
年表(Chronology)
时区(Time zone)
我将针对 Joda 依次讨论每一个概念。
不可变性
我在本文讨论的 Joda 类具有不可变性,因此它们的实例无法被修改。(不可变类的一个优点就是它们是线程安全的)。我将向您展示的用于处理日期计算的 API 方法全部返回一个对应 Joda 类的新实例,同时保持原始实例不变。当您通过一个 API 方法操作 Joda 类时,您必须捕捉该方法的返回值,因为您正在处理的实例不能被修改。您可能对这种模式很熟悉;比如,这正是 java.lang.String 的各种操作方法的工作方式。
瞬间性
Instant 表示时间上的某个精确的时刻,使用从 epoch 开始计算的毫秒表示。这一定义与 JDK 相同,这就是为什么任何 Joda Instant 子类都可以与 JDK Date 和 Calendar 类兼容的原因。
更通用一点的定义是:一个瞬间 就是指时间线上只出现一次且唯一的一个时间点,并且这种日期结构只能以一种有意义的方式出现一次。
局部性
一个局部时间,正如我将在本文中将其称为局部时间片段一样,它指的是时间的一部分片段。瞬间性指定了与 epoch 相对的时间上的一个精确时刻,与此相反,局部时间片段指的是在时间上可以来回 “移动” 的一个时刻,这样它便可以应用于多个实例。比如,6 月 2 日 可以应用于任意一年的 6 月份(使用 Gregorian 日历)的第二天的任意瞬间。同样,11:06 p.m. 可以应用于任意一年的任意一天,并且每天只能使用一次。即使它们没有指定一个时间上的精确时刻,局部时间片段仍然是有用的。
我喜欢将局部时间片段看作一个重复周期中的一点,这样的话,如果我正在考虑的日期构建可以以一种有意义的方式出现多次(即重复的),那么它就是一个局部时间。
年表
Joda 本质 — 以及其设计核心 — 的关键就是年表(它的含义由一个同名抽象类捕捉)。从根本上讲,年表是一种日历系统 — 一种计算时间的特殊方式 — 并且是一种在其中执行日历算法的框架。受 Joda 支持的年表的例子包括:
ISO(默认)
Coptic
Julian
Islamic
Joda-Time 1.6 支持 8 种年表,每一种都可以作为特定日历系统的计算引擎。
时区
时区是值一个相对于英国格林威治的地理位置,用于计算时间。要了解事件发生的精确时间,还必须知道发生此事件的位置。任何严格的时间计算都必须涉及时区(或相对于 GMT),除非在同一个时区内发生了相对时间计算(即时这样时区也很重要,如果事件对于位于另一个时区的各方存在利益关系的话)。
DateTimeZone 是 Joda 库用于封装位置概念的类。许多日期和时间计算都可以在不涉及时区的情况下完成,但是仍然需要了解 DateTimeZone 如何影响 Joda 的操作。默认时间,即从运行代码的机器的系统时钟检索到的时间,在大部分情况下被使用。
创建 Joda-Time 对象
现在,我将展示在采用该库时会经常遇到的一些 Joda 类,并展示如何创建这些类的实例。
可变的 Joda 类
我并不是可变实用类的粉丝;我只是认为它们的用例并不适合广泛使用。但是如果您认为您的确需要使用可变 Joda 类的话,本节的内容应当会对您的项目有帮助。Readable 和ReadWritable API 之间的唯一区别在于 ReadWritable 类能够改变封装的日期/时间值,因此我在这里将不再介绍这一点。
本节中介绍的所有实现都具有若干构造函数,允许您初始化封装的日期/时间。它们可以分为 4 个类别:
使用系统时间。
使用多个字段指定一个瞬间时刻(或局部时间片段),达到这个特定实现所能支持的最细粒度的精确度。
指定一个瞬间时刻(或局部时间片段),以毫秒为单位。
使用另一个对象(例如,java.util.Date,或者是另一个 Joda 对象)。
我将在第一个类中介绍这些构造函数: DateTime。当您使用其他 Joda 类的相应构造函数时,也可以使用这里介绍的内容。
重载方法
如果您创建了一个 DateTime 的实例,并且没有提供 Chronology 或 DateTimeZone,Joda 将使用 ISOChronology(默认)和 DateTimeZone(来自系统设置)。然而,Joda ReadableInstant 子类的所有构造函数都包含一个超载方法,该方法以一个Chronology 或 DateTimeZone 为参数。本文附带的应用程序的的样例代码展示了如何使用这些超载方法。我在这里不会再详细介绍它们,因为这些方法使用起来非常简单。然而,我建议您试着使用一下这个样例应用程序,看看编写您的应用程序代码有多么简单,这样您就可以随意地在 Joda 的 Chronology 和 DateTimeZone 之间切换,同时不会影响到代码的其余部分。
ReadableInstant
Joda 通过 ReadableInstant 类实现了瞬间性这一概念。表示时间上的不可变瞬间的 Joda 类都属于这个类的子类。(将这个类命名为ReadOnlyInstant 可能更好,我认为这才是设计者需要传达的意思)。换句话说,ReadableInstant 表示时间上的某一个不可修改的瞬间)。其中的两个子类分别为 DateTime 和 DateMidnight:
DateTime:这是最常用的一个类。它以毫秒级的精度封装时间上的某个瞬间时刻。DateTime 始终与 DateTimeZone 相关,如果您不指定它的话,它将被默认设置为运行代码的机器所在的时区。 可以使用多种方式构建 DateTime 对象。这个构造函数使用系统时间:
DateTime dateTime = new DateTime();
一般来讲,我会尽量避免使用系统时钟来初始化应用程序的实际,而是倾向于外部化设置应用程序代码使用的系统时间。样例应用程序执行以下代码:
DateTime dateTime = SystemFactory.getClock().getDateTime();
这使得使用不同日期/时间测试我的代码变得更加简单:我不需要修改代码来在应用程序中运行不同的日期场景,因为时间是在 SystemClock 实现的内部设置的,而不是在应用程序的内部。(我可以修改系统时间,但是那实在太痛苦了!) 下面的代码使用一些字段值构建了一个 DateTime 对象:正如您所见,Joda 可以使您精确地控制创建 DateTime 对象的方式,该对象表示时间上的某个特定的瞬间。每一个 Joda 类都有一个与此类似的构造函数,您在此构造函数中指定 Joda 类可以包含的所有字段。您可以用它快速了解特定类在哪一种粒度级别上操作。下一个构造函数将指定从 epoch 到某个时刻所经过的毫秒数。它根据 JDK Date 对象的毫秒值创建一个 DateTime 对象,其时间精度用毫秒表示,因为 epoch 与 Joda 是相同的:
java.util.Date jdkDate = obtainDateSomehow(); long timeInMillis = jdkDate.getTime(); DateTime dateTime = new DateTime(timeInMillis);
并且这个例子与前例类似,唯一不同之处是我在这里将 Date 对象直接传递给构造函数:
java.util.Date jdkDate = obtainDateSomehow(); dateTime = new DateTime(jdkDate);
Joda 支持使用许多其他对象作为构造函数的参数,用于创建 DateTime,如清单 5 所示:
清单 5. 直接将不同对象传递给 DateTime 的构造函数
// Use a Calendar java.util.Calendar calendar = obtainCalendarSomehow(); dateTime = new DateTime(calendar); // Use another Joda DateTime DateTime anotherDateTime = obtainDateTimeSomehow(); dateTime = new DateTime(anotherDateTime); // Use a String (must be formatted properly) String timeString = "2006-01-26T13:30:00-06:00"; dateTime = new DateTime(timeString); timeString = "2006-01-26"; dateTime = new DateTime(timeString);
注意,如果您准备使用 String(必须经过解析),您必须对其进行精确地格式化。参考 Javadoc,获得有关 Joda 的 ISODateTimeFormat 类的更多信息。
DateMidnight:这个类封装某个时区(通常为默认时区)在特定年/月/日的午夜时分的时刻。它基本上类似于 DateTime,不同之处在于时间部分总是为与该对象关联的特定 DateTimeZone 时区的午夜时分。
您将在本文看到的其他类都遵循与 ReadableInstant 类相同的模式(Joda Javadoc 将显示这些内容),因此为了节省篇幅,我将不会在以下小节介绍这些内容。
ReadablePartial
应用程序所需处理的日期问题并不全部都与时间上的某个完整时刻有关,因此您可以处理一个局部时刻。例如,有时您比较关心年/月/日,或者一天中的时间,甚至是一周中的某天。Joda 设计者使用 ReadablePartial 接口捕捉这种表示局部时间的概念,这是一个不可变的局部时间片段。用于处理这种时间片段的两个有用类分别为 LocalDate 和 LocalTime:
LocalDate:该类封装了一个年/月/日的组合。当地理位置(即时区)变得不重要时,使用它存储日期将非常方便。例如,某个特定对象的出生日期 可能为 1999 年 4 月 16 日,但是从技术角度来看,在保存所有业务值的同时不会了解有关此日期的任何其他信息(比如这是一周中的星期几,或者这个人出生地所在的时区)。在这种情况下,应当使用 LocalDate。 样例应用程序使用 SystemClock 来获取被初始化为系统时间的 LocalDate 的实例:
也可以通过显式地提供所含的每个字段的值来创建 LocalDate:
LocalDate localDate = SystemFactory.getClock().getLocalDate(); LocalDate 替代了在早期 Joda 版本中使用的 YearMonthDay。 LocalDate localDate = new LocalDate(2009, 9, 6);// September 6, 2009
LocalTime:这个类封装一天中的某个时间,当地理位置不重要的情况下,可以使用这个类来只存储一天当中的某个时间。例如,晚上 11:52 可能是一天当中的一个重要时刻(比如,一个 cron 任务将启动,它将备份文件系统的某个部分),但是这个时间并没有特定于某一天,因此我不需要了解有关这一时刻的其他信息。 样例应用程序使用 SystemClock 获取被初始化为系统时间的 LocalTime 的一个实例:
也可以通过显式地提供所含的每个字段的值来创建 LocalTime:
LocalTime localTime = new LocalTime(13, 30, 26, 0);// 1:30:26PM LocalTime localTime = SystemFactory.getClock().getLocalTime();
了解特定的时刻或是某个局部时间片段将非常有用,但是如果能够表达一段时间跨度的话,通常也很有用。Joda 提供了三个类来简化这个过程。您可以选择用于表示不同跨度的类:时间跨度
Duration:这个类表示一个绝对的精确跨度,使用毫秒为单位。这个类提供的方法可以用于通过标准的数学转换(比如 1 分钟 = 60 秒,1 天 = 24 小时),将时间跨度转换为标准单位(比如秒、分和小时)。 您只在以下情况使用 Duration 的实例:您希望转换一个时间跨度,但是您并不关心这个时间跨度在何时发生,或者使用毫秒处理时间跨度比较方便。
Period:这个类表示与 Duration 相同的概念,但是以人们比较熟悉的单位表示,比如年、月、周。 您可以在以下情况使用 Period:您并不关心这段时期必须在何时发生,或者您更关心检索单个字段的能力,这些字段描述由 Period 封装的时间跨度。
Interval:这个类表示一个特定的时间跨度,将使用一个明确的时刻界定这段时间跨度的范围。Interval 为半开 区间,这表示由 Interval 封装的时间跨度包括这段时间的起始时刻,但是不包含结束时刻。 可以在以下情况使用 Interval:需要表示在时间连续区间中以特定的点开始和结束的一段时间跨度。
以 Joda 的方式处理时间
现在,您已经了解了如何创建一些非常有用的 Joda 类,我将向您展示如何使用它们执行日期计算。接着您将了解到 Joda 如何轻松地与 JDK 进行互操作。
日期计算
如果您只是需要对日期/时间信息使用占位符,那么 JDK 完全可以胜任,但是它在日期/时间计算方面的表现十分糟糕,而这正是 Joda 的长处。我将向您展示一些简单的例子。
假设在当前的系统日期下,我希望计算上一个月的最后一天。对于这个例子,我并不关心一天中的时间,因为我只需要获得年/月/日,如清单 6 所示:
清单 6. 使用 Joda 计算日期
LocalDate now = SystemFactory.getClock().getLocalDate(); LocalDate lastDayOfPreviousMonth =\ now.minusMonths(1).dayOfMonth().withMaximumValue();
您可能对清单 6 中的 dayOfMonth() 调用感兴趣。这在 Joda 中被称为属性(property)。它相当于 Java 对象的属性。属性是根据所表示的常见结构命名的,并且它被用于访问这个结构,用于完成计算目的。属性是实现 Joda 计算威力的关键。您目前所见到的所有 4 个 Joda 类都具有这样的属性。一些例子包括:
yearOfCentury
dayOfYear
monthOfYear
dayOfMonth
dayOfWeek
我将详细介绍清单 6 中的示例,以向您展示整个计算过程。首先,我从当前月份减去一个月,得到 “上一个月”。接着,我要求获得 dayOfMonth 的最大值,它使我得到这个月的最后一天。注意,这些调用被连接到一起(注意 JodaReadableInstant 子类是不可变的),这样您只需要捕捉调用链中最后一个方法的结果,从而获得整个计算的结果。
当计算的中间结果对我不重要时,我经常会使用这种计算模式。(我以相同的方式使用 JDK 的 BigDecimal)。假设您希望获得任何一年中的第 11 月的第一个星期二的日期,而这天必须是在这个月的第一个星期一之后。清单 7 展示了如何完成这个计算:
清单 7. 计算 11 月中第一个星期一之后的第一个星期二
LocalDate now = SystemFactory.getClock().getLocalDate(); LocalDate electionDate = now.monthOfYear() .setCopy(11) // November .dayOfMonth() // Access Day Of Month Property .withMinimumValue() // Get its minimum value .plusDays(6) // Add 6 days .dayOfWeek() // Access Day Of Week Property .setCopy("Monday") // Set to Monday (it will round down) .plusDays(1); // Gives us Tuesday
清单 7 的注释帮助您了解代码如何获得结果。.setCopy("Monday") 是整个计算的关键。不管中间 LocalDate 值是多少,将其 dayOfWeek 属性设置为 Monday 总是能够四舍五入,这样的话,在每月的开始再加上 6 天就能够让您得到第一个星期一。再加上一天就得到第一个星期二。Joda 使得执行此类计算变得非常容易。
下面是其他一些因为使用 Joda 而变得超级简单的计算:
以下代码计算从现在开始经过两个星期之后的日期:
DateTime now = SystemFactory.getClock().getDateTime(); DateTime then = now.plusWeeks(2);
您可以以这种方式计算从明天起 90 天以后的日期:
DateTime now = SystemFactory.getClock().getDateTime(); DateTime tomorrow = now.plusDays(1); DateTime then = tomorrow.plusDays(90);
(是的,我也可以向 now 加 91 天,那又如何呢?)
下面是计算从现在起 156 秒之后的时间:
DateTime now = SystemFactory.getClock().getDateTime(); DateTime then = now.plusSeconds(156);
下面的代码将计算五年后的第二个月的最后一天:1
DateTime now = SystemFactory.getClock().getDateTime(); DateTime then = now.minusYears(5) // five years ago .monthOfYear() // get monthOfYear property .setCopy(2) // set it to February .dayOfMonth() // get dayOfMonth property .withMaximumValue();// the last day of the month
这样的例子实在太多了,我向您已经知道了如何计算。尝试操作一下样例应用程序,亲自体验一下使用 Joda 计算任何日期是多么有趣。
JDK 互操作性
我的许多代码都使用了 JDK Date 和 Calendar 类。但是幸亏有 Joda,我可以执行任何必要的日期算法,然后再转换回 JDK 类。这将两者的优点集中到一起。您在本文中看到的所有 Joda 类都可以从 JDK Calendar 或 Date 创建,正如您在 中看到的那样。出于同样的原因,可以从您所见过的任何 Joda 类创建 JDK Calendar 或 Date。
清单 8 展示了从 Joda ReadableInstant 子类转换为 JDK 类有多么简单:
清单 8. 从 Joda DateTime 类创建 JDK 类
DateTime dateTime = SystemFactory.getClock().getDateTime(); Calendar calendar = dateTime.toCalendar(Locale.getDefault()); Date date = dateTime.toDate(); DateMidnight dateMidnight = SystemFactory.getClock() .getDateMidnight(); date = dateMidnight.toDate();
对于 ReadablePartial 子类,您还需要经过额外一步,如清单 9 所示:
清单 9. 创建表示 LocalDate 的 Date 对象
LocalDate localDate = SystemFactory.getClock().getLocalDate(); Date date = localDate.toDateMidnight().toDate();
要创建 Date 对象,它表示从清单 9 所示的 SystemClock 中获得的 LocalDate,您必须首先将它转换为一个 DateMidnight 对象,然后只需要将 DateMidnight 对象作为 Date。(当然,产生的 Date 对象将把它自己的时间部分设置为午夜时刻)。
JDK 互操作性被内置到 Joda API 中,因此您无需全部替换自己的接口,如果它们被绑定到 JDK 的话。比如,您可以使用 Joda 完成复杂的部分,然后使用 JDK 处理接口。
以 Joda 方式格式化时间
使用 JDK 格式化日期以实现打印是完全可以的,但是我始终认为它应该更简单一些。这是 Joda 设计者进行了改进的另一个特性。要格式化一个 Joda 对象,调用它的 toString() 方法,并且如果您愿意的话,传递一个标准的 ISO-8601 或一个 JDK 兼容的控制字符串,以告诉 JDK 如何执行格式化。不需要创建单独的 SimpleDateFormat 对象(但是 Joda 的确为那些喜欢自找麻烦的人提供了一个 DateTimeFormatter 类)。调用 Joda 对象的 toString() 方法,仅此而已。我将展示一些例子。
清单 10 使用了 ISODateTimeFormat 的静态方法:
清单 10. 使用 ISO-8601
DateTime dateTime = SystemFactory.getClock().getDateTime(); dateTime.toString(ISODateTimeFormat.basicDateTime()); dateTime.toString(ISODateTimeFormat.basicDateTimeNoMillis()); dateTime.toString(ISODateTimeFormat.basicOrdinalDateTime()); dateTime.toString(ISODateTimeFormat.basicWeekDateTime());
清单 10 中的四个 toString() 调用分别创建了以下内容:
20090906T080000.000-0500 20090906T080000-0500 2009249T080000.000-0500 2009W367T080000.000-0500
您也可以传递与 SimpleDateFormat JDK 兼容的格式字符串,如清单 11 所示:
清单 11. 传递 SimpleDateFormat 字符串
DateTime dateTime = SystemFactory.getClock().getDateTime(); dateTime.toString("MM/dd/yyyy hh:mm:ss.SSSa"); dateTime.toString("dd-MM-yyyy HH:mm:ss"); dateTime.toString("EEEE dd MMMM, yyyy HH:mm:ssa"); dateTime.toString("MM/dd/yyyy HH:mm ZZZZ"); dateTime.toString("MM/dd/yyyy HH:mm Z"); 09/06/2009 02:30:00.000PM 06-Sep-2009 14:30:00 Sunday 06 September, 2009 14:30:00PM 09/06/2009 14:30 America/Chicago 09/06/2009 14:30 -0500
查看 Javadoc 中有关 joda.time.format.DateTimeFormat 的内容,获得与 JDK SimpleDateFormat 兼容的格式字符串的更多信息,并且可以将其传递给 Joda 对象的 toString() 方法。
结束语
谈到日期处理,Joda 是一种令人惊奇的高效工具。无论您是计算日期、打印日期,或是解析日期,Joda 都将是工具箱中的便捷工具。在本文中,我首先介绍了 Joda,它可以作为 JDK 日期/时间库的替代选择。然后介绍了一些 Joda 概念,以及如何使用 Joda 执行日期计算和格式化。
有什么问题可以扫码关注微信公众号:我是攻城师(woshigcs),在后台留言咨询。
技术债不能欠,健康债更不能欠, 求道之路,我们同行。

发表评论
-
记一次log4j不打印日志的踩坑记
2019-09-22 01:58 1655### 起因 前几天一个跑有java应用的生产集群(200多 ... -
在Java里面如何解决进退两难的jar包冲突问题?
2019-07-23 19:10 1296如上图所示: es api组件依赖guava18.0 ... -
如何轻松理解二叉树的深度遍历策略
2019-07-03 23:33 1196我们知道普通的线性数据结构如链表,数组等,遍历方式单一 ... -
为什么单线程Redis性能也很出色
2019-01-21 18:02 2266高性能的服务器,不一 ... -
如何将编程语言里面的字符串转成数字?
2019-01-11 23:23 2162将字符串转成数字在很 ... -
为什么Java里面String类是不可变的
2019-01-06 18:36 1724在Java里面String类型是不可变对象,这一点毫无疑问,那 ... -
关于Java里面volatile关键字的重排序
2019-01-04 18:49 1116Java里面volatile关键字主 ... -
多个线程如何轮流打印ABC特定的次数?
2018-12-11 20:42 6100之前的一篇文章,我给 ... -
聊聊Java里面的引用传递
2018-11-16 21:21 1016长久以来,在Java语言里面一直有一个争论,就是Java语言到 ... -
理解计数排序算法的原理和实现
2018-10-11 10:03 2122计数排序(Counting sort) ... -
理解Java7和8里面HashMap+ConcurrentHashMap的扩容策略
2018-09-06 11:31 3420### 前言 理解HashMap和Con ... -
关于Java里面多线程同步的一些知识
2018-07-18 09:45 1139# 关于Java里面多线程同步的一些知识 对于任何Java开 ... -
Java单例模式之双检锁深入思考
2018-07-08 12:25 3338# Java单例模式之双检锁 ... -
关于Java里面多线程同步的一些知识
2018-07-08 12:23 1147# 关于Java里面多线程同步的一些知识 对于任何Java开 ... -
重新认识同步与异步,阻塞和非阻塞的概念
2018-07-06 14:30 1503# 重新认识同步与异步 ... -
线程的基本知识总结
2018-06-27 16:27 1083### (一)创建线程的方式 (1)实现Runnable接口 ... -
Java里面volatile关键字修饰引用变量的陷阱
2018-06-25 11:42 1420# Java里面volatile关键字修饰引用变量的陷阱 如 ... -
关于Java里面的字符串拼接,你了解多少?
2018-06-25 11:28 1410# 关于Java里面的字符串 ... -
深入理解Java内存模型的语义
2018-06-25 11:39 768### 前言 Java内存模型( ... -
如何证明Java多线程中的成员变量数据是互不可见的
2018-06-21 10:09 1543前面的几篇文章主要介绍了Java的内存模型,进程和线程的定义, ...
相关推荐
Joda-Time是Java社区中广泛使用的日期和时间处理库,它弥补了Java内置日期时间API的不足,提供了更灵活且功能丰富的API。DowntimeCalc利用Joda-Time的强大力量,可以精确地处理日期时间间隔,这对于计算停机时间和...
wdaaaaaaaaaafwawfw
scratch少儿编程逻辑思维游戏源码-十字鸭子.zip
Android移动应用开发_ViewFlow自定义控件CircleFlowIndicator指示器网络图片加载缓存自动循环滚动手势滑动交互_横向循环平滑滚动广告条Banne
前端开发_基于jQuery和EasyUI框架_企业级Web应用UI组件库与后台管理系统模板_提供GPL开源版本和商业授权版本的双重授权模式_适用于快速构建响应式管理后台和复杂数据可
《C++编程实例100篇》是一本深入实践、极具价值的编程教程,它针对C++编程语言提供了丰富的实例,旨在帮助读者更好地理解和掌握C++的各项特性与编程技巧。这本书的经典之处在于它将理论与实践相结合,通过100个精心设计的编程实例,覆盖了C++的各个核心领域,包括基础语法、面向对象编程、模板、异常处理、STL(标准模板库)等。 我们来探讨C++的基础语法。C++是C语言的增强版,它保留了C语言的高效性和灵活性,并引入了类、对象和继承等面向对象编程概念。基础语法包括变量声明、数据类型、运算符、控制结构(如if语句、for循环、while循环)、函数的定义和调用等。在实例中,你可能会遇到如何编写简单的程序,如计算两个数的和,或者实现一个简单的猜数字游戏。 C++的面向对象编程是其一大特色。通过类和对象,你可以构建复杂的软件系统。类是对象的蓝图,它定义了对象的属性和行为。实例化一个类,就是创建一个具体的对象。继承允许你创建新的类,这些类从现有的类派生,共享其属性和方法,同时可以添加新的功能。多态性是面向对象的另一个关键特性,它使得不同类型的对象可以对同一消息作出不同的响应。这些概念在实例中会以各种形式展现,例如设计一个图形界面的类层次,或实现一个简单的模拟游戏。 接下来是模板,C++的模板功能让代码更加通用,可以处理不同类型的数据。模板分为函数模板和类模板,前者可以创建泛型函数,后者可以创建泛型类。通过模板,你可以编写出高效且灵活的代码,比如实现一个通用的排序算法。 异常处理是C++中用于处理程序运行时错误的机制。当程序出现异常情况时,可以抛出一个异常,然后在适当的点捕获并处理这个异常。这使得代码能够优雅地处理错误,而不是让程序崩溃。实例中可能会有涉及文件操作或网络通信时可能出现的异常处理示例。
scratch少儿编程逻辑思维游戏源码-忍者无限跑者.zip
少儿编程scratch项目源代码文件案例素材-战斗机游戏.zip
手工DIY行业_微信小程序云开发_手工坊预约管理系统_基于腾讯云开发技术的手工DIY行业线上线下结合解决方案_包含手工项目展示预约管理签到核销数据统计等完整功能_支持后台时段设置人
内容概要:本文档汇总了FFmpeg工具的多个实用命令示例,涵盖音频和视频处理的各个方面。包括但不限于:音频采样率转换、音频格式转为raw、查询音频文件时长与音量检测、调整音频音量大小、改变音频播放速度、视频逆序播放(针对无音频视频)、精准视频片段截取、音频片段截取、视频与音频合并处理、调整视频宽高比等。每个命令都提供了具体的参数设置方法; 适合人群:音视频编辑爱好者、多媒体处理领域的初学者或有一定经验的技术人员; 使用场景及目标:①在音频处理方面,可以完成从格式转换到音质调整的任务;②在视频处理上,能够实现基本的剪辑操作如切割、翻转、合并等;③为用户提供了一站式的解决方案,帮助用户快速掌握FFmpeg命令行工具的基本用法,提高工作效率; 阅读建议:本指南以命令实例为主,建议读者结合实际需求选择相应的命令进行尝试,在实践中理解各个参数的作用并灵活运用。
一、毕业设计的技术背景和设计依据 计算机硬盘驱动器作为一种存储数据信息的设备,在目前的计算机系统中起着不可替代的作用,读写的快慢对整个计算机系统的性能无疑占有重要地位。硬盘式电子计算机磁记录机构中最为精密的一类微机电系统设备,它对振动的敏感性是由其结构决定的,而其控制尚未很好的解决,针对硬盘展开建模及控制有着重要的实际应用价值。 二、毕业设计的任务 现代硬盘一般有 1 - 5 个盘片,以常见的 3.5 英寸硬盘为例,盘片直径约为 95mm,厚度约为 0.635mm。磁头数量通常与盘片数量相关,每面盘片有一个磁头,比如一个 3 盘片的硬盘就有 6 个磁头。缓存大小可能为 32MB、64MB 或 128MB 等,如某普通硬盘缓存为 64MB,电机功率一般在 2 - 5W,像转速为 7200RPM(转每分钟)的电机功率约 3W。数据写入时,磁头在电机带动下,以平均寻道速度约 10 - 15m/s 定位磁道。以一块顺序写入数据的硬盘为例,当写入连续大文件,如 1GB 的视频文件时,在 SATA3.0 接口下,理论传输带宽为 6Gb/s(约 750MB/s),实际可达 500 - 600MB/s。读取时,磁头感应盘片磁场变化,如读取小文件(1MB 大小),若磁头寻道距离平均为 1000 个磁道,每次寻道时间约 8 - 12ms,读取速度会因寻道而下降到 10 - 20MB/s。 本设计选取硬盘驱动器作为研究对象,假设电机扭矩为 0.3N・m,盘片转动惯量为 0.003kg・m²,轴承摩擦力矩为 0.03N・m。在稳定旋转阶段,转速波动范围设为额定转速的 ±0.5%,即 ±36RPM。首先通过对该系统分析建立了其物理模型,然后针对以音圈电机作为伺服机构的硬盘磁头定位伺服系统的性能要求,对音圈电机的控制设计采用三种控制器方案,即极点配置法、PID控制方法、线性二次型调节器方法,分别比较分
scratch少儿编程逻辑思维游戏源码-猫猫冲刺.zip
大数据处理_全文搜索引擎_ElasticSearch中文发行版_基于最新稳定版ElasticSearch预集成中文分词插件及常用配置的开箱即用解决方案_专为中文开发者优化的免配置高
离散数学_逻辑演算系统_真值表生成器_主范式计算器_最简范式求解器_王浩算法实现_等值演算工具_命题逻辑分析平台_基于Web的交互式逻辑运算系统_用于离散数学教学与研究的综合性逻辑
商业智能_SpringBoot_MQ_AIGC_React_智能数据分析_可视化图表_自动分析_数据集处理_用户诉求解析_数据降本增效_基于人工智能的商业智能分析平台_通过自然语言
少儿编程scratch项目源代码文件案例素材-爪猫小车.zip
少儿编程scratch项目源代码文件案例素材-拽猫挥剑.zip
kuishou68_neteaseMusic_32152_1745866029873
少儿编程scratch项目源代码文件案例素材-种族叛徒.zip
scratch少儿编程逻辑思维游戏源码-色彩交换.zip