关于date4j,简约的日期处理库(Java's Date Classes Must Die.)

标签: date4j 日期 java | 发表时间:2012-04-12 01:05 | 作者:kohri
出处:http://www.blogjava.net/

      在熟悉公司业务代码的时候经常看见有日期处理(date),由于项目转手次数较多,在这方面没合理封装处理好,于是就想自己封装一个date类。然而辗转了几天却发觉已经有date4j的存在,于是在这里简单地介绍一下这个日期类库。以下包括自己的代码、网上流传资料、以及date4j官网例子。

-------------------------------------------------------------------------------------------------------------------------------------------------------------

java日期处理相关类:

java.util.Date 
java.sql.Date 
java.sql.Time 
java.sql.Timestamp 
java.util.Calendar 
java.util.TimeZone

     比较常用的是java.util.date,将java.util.Date转为java.sql.Date的时候,日期时分秒会被去掉,失去精度。而且如果现在翻开api看看就发觉这两个类好多方法已经过时,几近沦为废物。

     Timestamp能和java.util.date无损转换,但是在一些预定义sql中会常常出问题。

(以上出自  click me

--------------------------------------------------------------------------------------------------------------------------------------------------------------

Java本身的日期类在JDK1.0版本之后就再也没有更新过,同时还存在着一些众所周知的问题(例如1月从0开始,导致了很多月份差一的漏洞)。一份新的Java规范请求(JSR,Java Specification Request)已经被提交,目的就是要解决上述问题,此版本的类库仍处在Alpha版本。在其稳定之前,很多开发者还是会使用Joda Time类库,该类库与JSR-310的参考实现类似(但不完全相同)。 Date4j为在Java中处理日期提供了一套新的解决方案,但与Joda Time所关注的范围完全不同。对比如下:

Joda Time Date4j
拥有的类的数量:  140+ 拥有的类的数量 < 10
包含可变和不可变类 仅包含不可变类
强调速度和功能 强调简单和有效
支持格里高里历(Gregorian)、 科普特语日历(Coptic)、 伊斯兰教历(Islamic)、佛历(Buddhist)等等 只提供对格里高里历的支持
可以完全取代JDK日期类 和JDK日期类配合使用
精确到毫秒级操作 支持到纳秒(十亿分之一秒)级操作
修复了天“溢出”的问题 天“溢出”的问题可配置
针对的是通常意义的日期维护 适用于通过数据库来维护的日期
采用Apache 2.0授权许可 采用BSD授权许可

虽然乍一看Date4j只具备了Joda中一部分的特性,但它有两个主要的特点是Joda所不具备的。

首先,Date4j的开发者 宣称类库不应莫名其妙地将日期截断。Joda只支持毫秒级的精度而且在将来 可能也不会改善。一些数据库也已经有了更好的解决方案。比如流行的 PostgreSQL数据库对时间戳精度就已经支持到 微秒级(百万分之一秒)。Date4j可在处理日期时对精度毫无损伤。

第二个特征是日期“溢出”的问题,例如向某个日期增加一段时间后,日期落在下月的情况。最简单的例子就是在3月31日增加一个月的计算:

DateTime dt = new DateTime("2011-03-31");    
DateTime result = dt.plusMonths(1); (最新版本此方法应该已经被删除,只有plus(...)与plusDay())
System.out.println(result.toString());

当使用Joda Time时,会输出4月30日,但这也许并不是你想要的结果。

鉴于这种不确定性,Date4j为您提供了 4种选择

1. 第一天
2. 最后一天(与Joda Time相同)
3. 日期顺延
4. 抛出异常

以上转自 click me
-----------------------------------------------------------------------------------------------------------------------------------------------------------

date4j官网&&实例:


import hirondelle.date4j.DateTime;
import hirondelle.date4j.DateTime.DayOverflow;

import java.util.TimeZone;

public class Date4jExamples {

    public static void main(String[] args) {
        Date4jExamples examples = new Date4jExamples();
        examples.currentDateTime();
        examples.ageIfBornOnCertainDate();
        examples.daysTillChristmas();
        examples.whenIs90DaysFromToday();
        examples.dateDifference();
        examples.whenIs3Months5DaysFromToday();
        examples.hoursDifferenceBetweenParisAndPerth();
        examples.weeksSinceStart();
        examples.timeTillMidnight();
        examples.imitateISOFormat();
        examples.firstDayOfThisWeek();
        examples.jdkDatesSuctorial();

    }

    private static void log(Object aMsg) {
        System.out.println(String.valueOf(aMsg));
    }

    /**
     * 获取当前时间 what is the current date-time in the JRE's default time zone
     * ------------------------------------------------------------------------
     * Here are some practical examples of using the above formatting symbols:
     * Format Output YYYY-MM-DD hh:mm:ss.fffffffff a 1958-04-09
     * 03:05:06.123456789 AM YYYY-MM-DD hh:mm:ss.fff a 1958-04-09 03:05:06.123
     * AM YYYY-MM-DD 1958-04-09 hh:mm:ss.fffffffff 03:05:06.123456789 hh:mm:ss
     * 03:05:06 YYYY-M-D h:m:s 1958-4-9 3:5:6 WWWW, MMMM D, YYYY Wednesday,
     * April 9, 1958 WWWW, MMMM D, YYYY |at| D a Wednesday, April 9, 1958 at 3
     * AM ----------------------------------------------------------------------
     * ---
     */
    private void currentDateTime() {
        DateTime now = DateTime.now(TimeZone.getDefault());
        String result = now.format("YYYY-MM-DD hh:mm:ss");
        log("Current date-time in default time zone : " + result);
        // result Current date-time in default time zone : 2012-04-12 00:55:54
    }

    /**
     * 年龄计算 what's the age of someone born may 16,1995
     */
    private void ageIfBornOnCertainDate() {
        DateTime today = DateTime.today(TimeZone.getDefault());
        DateTime birthdate = DateTime.forDateOnly(1995, 5, 16);
        int age = today.getYear() - birthdate.getYear();
        // getDayOfYear获取距离年初的总天数
        if (today.getDayOfYear() < birthdate.getDayOfYear()) {
            age = age - 1;
        }
        log("Age of someone born May 16, 1995 is : " + age);
        // result Age of someone born May 16, 1995 is : 16
    }

    /**
     * 日期相距 How many days till the next December 25
     */
    private void daysTillChristmas() {
        DateTime today = DateTime.today(TimeZone.getDefault());
        DateTime christmas = DateTime.forDateOnly(today.getYear(), 12, 25);
        int result = 0;
        if (today.isSameDayAs(christmas)) {
            // do nothing
        } else if (today.lt(christmas)) {
            result = today.numDaysFrom(christmas);
        } else if (today.gt(christmas)) {
            DateTime christmasNextYear = DateTime.forDateOnly(
                    today.getYear() + 1, 12, 25);
            result = today.numDaysFrom(christmasNextYear);
        }
        log("Number of days till Christmas : " + result);
        // result Number of days till Christmas : 257
    }

    /**
     * What day is 90 days from today
     */
    private void whenIs90DaysFromToday() {
        DateTime today = DateTime.today(TimeZone.getDefault());
        log("90 days from today is : "
                + today.plusDays(90).format("YYYY-MM-DD"));
        // result 90 days from today is : 2012-07-11
    }

    /**
     * 日期相差
     */
    private void dateDifference() {
        // DayOverflow.Abort result throw Exception
        // DayOverflow.Spillover result 2011-05-01
        // DayOverflow.LastDay result 2011-04-30
        // DayOverflow.FirstDay result 2011-05-01
        // public enum DayOverflow {
        /** Coerce the day to the last day of the month. */
        // LastDay,
        /** Coerce the day to the first day of the next month. */
        // FirstDay,
        /** Spillover the day into the next month. */
        // Spillover,
       /** Throw a RuntimeException. */
        // Abort;
        // }
        /**
         * @param aNumYears
         *            positive, required, in range 0 9999
         * @param aNumMonths
         *            positive, required, in range 0 9999
         * @param aNumDays
         *            positive, required, in range 0 9999
         * @param aNumHours
         *            positive, required, in range 0 9999
         * @param aNumMinutes
         *            positive, required, in range 0 9999
         * @param aNumSeconds
         *            positive, required, in range 0 9999 method plus(Integer
         *            aNumYears, Integer aNumMonths, Integer aNumDays, Integer
         *            aNumHours, Integer aNumMinutes, Integer aNumSeconds,
         *            DayOverflow aDayOverflow)
         * 
         */
        DateTime dt = new DateTime("2011-03-31");
        DateTime result = dt.plus(0, 1, 0, 0, 0, 0, DayOverflow.Spillover);
        log("date difference : " + result.toString());
        // result date difference : 2011-05-01 00:00:00
    }

    /** What day is 3 months and 5 days from today? */
    private void whenIs3Months5DaysFromToday() {
        DateTime today = DateTime.today(TimeZone.getDefault());
        DateTime result = today.plus(0, 3, 5, 0, 0, 0,
                DateTime.DayOverflow.FirstDay);
        log("3 months and 5 days from today is : "
                + result.format("YYYY-MM-DD"));
        // result 3 months and 5 days from today is : 2012-07-17
    }

    /**
     * Current number of hours difference between Paris, France and Perth,
     * Australia.
     */
    private void hoursDifferenceBetweenParisAndPerth() {
        // this assumes the time diff is a whole number of hours; other styles
        // are possible
        DateTime paris = DateTime.now(TimeZone.getTimeZone("Europe/Paris"));
        DateTime perth = DateTime.now(TimeZone.getTimeZone("Australia/Perth"));
        int result = perth.getHour() - paris.getHour();
        if (result < 0) {
            result = result + 24;
        }
        log("Numbers of hours difference between Paris and Perth : " + result);
        // result Numbers of hours difference between Paris and Perth : 6
    }

    /** How many weeks is it since Sep 6, 2010? */
    private void weeksSinceStart() {
        DateTime today = DateTime.today(TimeZone.getDefault());
        DateTime startOfProject = DateTime.forDateOnly(2010, 9, 6);
        int result = today.getWeekIndex() - startOfProject.getWeekIndex();
        log("The number of weeks since Sep 6, 2010 : " + result);
        // result The number of weeks since Sep 6, 2010 : 83
    }

    /** How much time till midnight? */
    private void timeTillMidnight() {
        DateTime now = DateTime.now(TimeZone.getDefault());
        DateTime midnight = now.plusDays(1).getStartOfDay();
        long result = now.numSecondsFrom(midnight);
        log("This many seconds till midnight : " + result);
        // result This many seconds till midnight : 83046
    }

    /** Format using ISO style. */
    private void imitateISOFormat() {
        DateTime now = DateTime.now(TimeZone.getDefault());
        log("Output using an ISO format: " + now.format("YYYY-MM-DDThh:mm:ss"));
        // result Output using an ISO format: 2012-04-12T00:55:54
    }

    private void firstDayOfThisWeek() {
        DateTime today = DateTime.today(TimeZone.getDefault());
        DateTime firstDayThisWeek = today; // start value
        int todaysWeekday = today.getWeekDay();
        int SUNDAY = 1;
        if (todaysWeekday > SUNDAY) {
            int numDaysFromSunday = todaysWeekday - SUNDAY;
            firstDayThisWeek = today.minusDays(numDaysFromSunday);
        }
        log("The first day of this week is : " + firstDayThisWeek);
        // result The first day of this week is : 2012-04-08
    }

    /** For how many years has the JDK date-time API been suctorial? */
    private void jdkDatesSuctorial() {
        DateTime today = DateTime.today(TimeZone.getDefault());
        DateTime jdkFirstPublished = DateTime.forDateOnly(1996, 1, 23);
        int result = today.getYear() - jdkFirstPublished.getYear();
        log("The number of years the JDK date-time API has been suctorial : "
                + result);
        // result The number of years the JDK date-time API has been suctorial :
        // 16
    }
}


kohri 2012-04-12 01:05 发表评论

相关 [date4j 日期 java] 推荐:

关于date4j,简约的日期处理库(Java's Date Classes Must Die.)

- - BlogJava-首页技术区
      在熟悉公司业务代码的时候经常看见有日期处理(date),由于项目转手次数较多,在这方面没合理封装处理好,于是就想自己封装一个date类. 然而辗转了几天却发觉已经有date4j的存在,于是在这里简单地介绍一下这个日期类库. 以下包括自己的代码、网上流传资料、以及date4j官网例子.      比较常用的是java.util.date,将java.util.Date转为java.sql.Date的时候,日期时分秒会被去掉,失去精度.

Java的日期API真烂

- - 四火的唠叨
文章系本人原创,转载请保持完整性并注明出自 《四火的唠叨》. 记得在我刚学Java的时候,真是搞不清楚Date和Calendar这两个类,后来我渐渐知道,原来不能全怪我啊,Java日期API之烂是公认的(不妨参见 这篇文章,Tiago Fernandez做过一个投票,就是要选举最烂的Java API,结果Java日期API排行第二,仅次于臭名远扬的EJB2,嘿嘿).

Java计算日期和时间差

- - BlogJava_首页
这篇文章将使用两个例子计算两个日期的时间差.  计算两个Date之间的时间差,基本思路为把Date转换为ms(微秒),然后计算两个微秒时间差. 1s秒 = 1000ms毫秒 1min分种 = 60s秒 1hours小时 = 60min分钟 1day天 = 24hours小时.             //毫秒ms.

Joda Time v2.0 发布,强大的Java日期时间库

- Jet - ITeye资讯频道
   Joda Time v2.0发布了.    Joda Time是一个强大、易用、高效的日期和时间库,它可以作为 JDK 日期/时间库的替代选择. 无论是计算日期、打印日期,或是解析日期,Joda 都将是非常实用、便捷的工具.    Joda-Time 令时间和日期值变得易于管理、操作和理解. 事实上,易于使用是 Joda 的主要设计目标.

Java 8新的时间日期库的20个使用示例

- - Java译站
除了 lambda表达式, stream以及几个小的改进之外,Java 8还引入了一套全新的时间日期API,在本篇教程中我们将通过几个简单的任务示例来学习如何使用Java 8的这套API. Java对日期,日历及时间的处理一直以来都饱受诟病,尤其是它决定将java.util.Date定义为可修改的以及 将SimpleDateFormat实现成非线程安全的.

Java中的锁(Locks in Java)

- - 并发编程网 - ifeve.com
原文链接 作者:Jakob Jenkov 译者:申章 校对:丁一. 锁像synchronized同步块一样,是一种线程同步机制,但比Java中的synchronized同步块更复杂. 因为锁(以及其它更高级的线程同步机制)是由synchronized同步块的方式实现的,所以我们还不能完全摆脱synchronized关键字( 译者注:这说的是Java 5之前的情况).

Java PaaS 对决

- 呆瓜 - IBM developerWorks 中国 : 文档库
本文为 Java 开发人员比较了三种主要的 Platform as a Service (PaaS) 产品:Google App Engine for Java、Amazon Elastic Beanstalk 和 CloudBees RUN@Cloud. 它分析了每种服务独特的技术方法、优点以及缺点,而且还讨论了常见的解决方法.

Java浮点数

- d0ngd0ng - 译言-电脑/网络/数码科技
Thomas Wang, 2000年3月. Java浮点数的定义大体上遵守了二进制浮点运算标准(即IEEE 754标准). IEEE 754标准提供了浮点数无穷,负无穷,负零和非数字(Not a number,简称NaN)的定义. 在Java开发方面,这些东西经常被多数程序员混淆. 在本文中,我们将讨论计算这些特殊的浮点数相关的结果.

Qt——转战Java?

- - 博客 - 伯乐在线
编者按:事实上,在跨平台开发方面,Qt仍是最好的工具之一,无可厚非,但Qt目前没有得到任何主流移动操作系统的正式支持. 诺基亚的未来计划,定位非常模糊,这也是令很多第三方开发者感到失望,因此将导致诺基亚屡遭失败的原因. Qt的主要开发者之一Mirko Boehm在博客上强烈讽刺Nokia裁了Qt部门的决定,称其为“绝望之举”,而非“策略变更”.

java 验证码

- - ITeye博客
// 创建字体,字体的大小应该根据图片的高度来定. // 随机产生160条干扰线,使图象中的认证码不易被其它程序探测到. // randomCode用于保存随机产生的验证码,以便用户登录后进行验证. // 随机产生codeCount数字的验证码. // 得到随机产生的验证码数字. // 产生随机的颜色分量来构造颜色值,这样输出的每位数字的颜色值都将不同.