您的位置:首页 > 编程语言 > Java开发

Java处理日期Joda-Time

2015-09-17 21:04 393 查看

Introduction

Joda Time is like an iceberg, 9/10ths of it is invisible to user-code.Many, perhaps most, applications will never need to see what's below the surface.This document provides an introduction to the Joda-Time API for theaverage user, not for the would-be API
developer.

The bulk of thetext is devoted to code snippets that display the most common usage scenariosin which the library classes are used. In particular, we cover the usage of thekeyDateTime,
Interval, Durationand Period classes.

We finish with a look at the important topic of formatting and parsing and a fewmore advanced topics.

Architecture Overview

Instants

Fields
Properties

Intervals
Durations
Periods
Chronology
TimeZones
Interface usage
Package structure

Working with DateTime

Construction
JDK Interoperability
Querying DateTimes

Acessing fields
Date fields
Time fields

Manipulating DateTimes

Modifying fields
DateTime methods
Using a MutableDateTime

Changing TimeZone
Changing Chronology

Input and Output

Formatters
Standard Formatters
Custom Formatters
Freaky Formatters

Advanced features

Change the Current Time
Converters
Security

Architecture Overview

The major building blocks of joda time are introduced below. These are the conceptsofinstant,
interval, duration, period,chronology andtimezones. We then say a few words about the roleof interfaces in the library design, which is a little different than the norm. Weend with a few words on package structure.
Usage examples for instant are delayed until thefollowing sections of the guide. Examples for interval, duration and period may befound in the appropriate section in the "Key Concepts" part of the documentation.

Instants

The most frequently used concept in Joda-Time is that of the instant.An Instant is defined asa moment in the datetime continuum specified as anumber of milliseconds from 1970-01-01T00:00Z.This definition of milliseconds is consistent with
that of the JDK inDateor Calendar. Interoperating between the two APIs is thus simple.

Within Joda-Time an instant is represented by theReadableInstant interface. The main implementationof this interface, and the class that the average API user needs to bemost familiar with, isDateTime. DateTime is immutable - and oncecreated
the values do not change. Thus, this class can safely be passed aroundand used in multiple threads without synchronization.

The millisecond instant can be converted to any date time field using aChronology.To assist with this, methods are provided onDateTime that act as getters for the most common date andtime fields.

We discuss the chronology concept a litte further on in this overview.

A companion mutable class to DateTime isMutableDateTime. Objectsof this class can be modified and are not thread-safe.

Other implementations of ReadableInstant include Instantand
DateMidnight.

Fields

The main API of DateTime has been kept small, limited to justget methods for each calendar field. So, for instance, the 'day-of-year' calendarfield would be retrieved by calling thegetDayOfYear() method. Fora complete list of fields and
their descriptions, see thefield reference.

Properties

There is much more power available, however, through the use of what is termed aproperty. Each calendar field is associated with such a property.Thus, 'day-of-year', whose value is directly returned by the methodgetDayOfYear(), is also
associated with the property returned bythe dayOfYear() method. The property class associated withDateTime isDateTime.Property.

Knowing the methods on the property is the secret to making the most of the API.We have more to say on the usage of properties later in this document.

Intervals

An interval in Joda-Time represents an interval of time from oneinstant to another instant. Both instants are fully specified instants in thedatetime continuum, complete with time zone.

Intervals are implemented as half-open, which is to say that the start instant isinclusive but the end instant is exclusive. The end is always greater than or equal to the start.Both end-points are restricted to having the same chronology and the
same time zone.

Two implementations are provided, Interval and MutableInterval,both are specializations ofReadableInterval.

Durations

A duration in Joda-Time represents a duration of time measured in milliseconds.The duration is often obtained from an interval.

Durations are a very simple concept, and the implementation is also simple.They have no chronology or time zone, and consist solely of the millisecond duration.

Durations can be added to an instant, or to eitherend of an interval to change those objects.In datetime maths you could say:

instant  +  duration  =  instant


Currently, there is only one implementation of the ReadableDurationinterface:Duration.

Periods

A period in Joda-Time represents a period of time defined in terms of fields,for example, 3 years 5 months 2 days and 7 hours.This differs from a duration in that it is inexact in terms of milliseconds.A period can only be resolved to an exact number
of milliseconds by specifying theinstant (including chronology and time zone) it is relative to.

For example, consider a period of 1 month.If you add this period to the 1st February (ISO) then you will get the 1st March.If you add the same period to the 1st March you will get the 1st April.But the duration added (in milliseconds) in these two cases
is very different.

As a second example, consider adding 1 day at the daylight savings boundary.If you use a period to do the addition then either 23 or 25 hours will be added as appropriate.If you had created a duration equal to 24 hours, then you would end up with the wrong
result.

Periods are implemented as a set of int fields.The standard set of fields in a period are years, months, weeks, days, hours, minutes, secondsand millis.ThePeriodType class allows this setof fields to be restricted, for example to elimate
weeks.This is significant when converting a duration or interval to a period, as the calculationneeds to know which period fields it should populate.

Methods exist on periods to obtain each field value.Periods are not associated with either a chronology or a time zone.

Periods can be added to an instant, or to eitherend of an interval to change those objects.In datetime maths you could say:

instant  +  period  =  instant


There are two implementations of the ReadablePeriod interface,Period andMutablePeriod.

Chronology

The Joda-Time design is based around theChronology. It is a calculation engine that supports the complexrules for a calendar system. It encapsulates the field objects, which are usedon demand to split the absolute time instant into recognisable
calendarfields like 'day-of-week'. It is effectively a pluggable calendar system.

The actual calculations of the chronology are split between theChronology class itself and the field classes -DateTimeField andDurationField.Together, the subclasses of these three classes form the bulk of the codein the library.Most
users will never need to use or refer directly to the subclasses.Instead, they will simply obtain the chronology and use it as a singleton, as follows:

Chronology coptic = CopticChronology.getInstance();


Internally, all the chronology, field, etc. classes are maintained as singletons.Thus there is an initial setup cost when using Joda-Time, but after that onlythe main API instance classes(DateTime,Interval,
Period, etc.)have creation and garbage collector costs.

Although the Chronology is key to the design, it is not key to using the API !!

For most applications, the Chronology can be ignored as it will default to theISOChronology. This is suitable for most uses.You would change it if you need accurate dates before October 15, 1582,or whenever the Julian calendar ceased in the territory you're
interested in).You'd also change it if you need a specific calendar like the Coptic calendar illustrated earlier.

TimeZones

The chronology class also supports the time zone functionality.This is applied to the underlying chronology via the decorator design pattern.TheDateTimeZone class providesaccess to the zones primarily through one factory method, as follows:

DateTimeZone zone = DateTimeZone.forID("Europe/London");


In addition to named time zones, Joda-Time also supports fixed time zones.The simplest of these is UTC, which is defined as a constant:

DateTimeZone zoneUTC = DateTimeZone.UTC;


Other fixed offset time zones can be obtained by a specialise factory method:

DateTimeZone zoneUTC = DateTimeZone.forOffsetHours(hours);


The TimeZone implementation is based on data provided by the publictz database,otherwise known as the Olson database.A full list of timezone ids can
be foundhere

Joda-Time provides a default time zone which is used in many operations when atime zone is not specified. This is similar in concept to the default time zoneof thejava.util.TimeZone class. The value can be accessed and updatedvia static methods:

DateTimeZone defaultZone = DateTimeZone.getDefault();
DateTimeZone.setDefault(myZone);


Interface usage

As you have seen, Joda-Time defines a number of new interfaces which are visiblethroughout the javadocs. The most important isReadableInstant whichcurrently has 4 implementations.Other significant interfaces includeReadableInterval andReadablePeriod.
These are currently used as generalizations fora value-only and a mutable class, respectively.

An important point to mention here is that the Joda interfaces are used differentlythan, for instance, the JDK Collections Framework interfaces.When working with a Collections interface, such asList or
Mapyou will normally hold your variable as a type of List or
Map, only referencing the concrete class when you create the object.

List list = new ArrayList();
    Map map = new HashMap();


In Joda-Time, the interfaces exist to allow interoperation between similardate implementations, such as a mutable and immutable version of a class.As such, they only offer a subset of the methods of the concrete class.For most work, you will reference
the concrete class, not the interface.This gives access to the full power of the library.

DateTime dt = new DateTime();


For maximum flexibility however, you might choose to declare your methodparameters using the Joda-Time interface.A method on the interface can obtain the concrete class for use within the method.

public void process(ReadableDateTime dateTime) {
        DateTime dt = dateTime.toDateTime();
    }


Package structure

The package structure is designed to separate the methods in the public APIfrom the private API.The public packages are the root package (underorg.joda.time) andthe
format package.The private packages are thebase, chrono,convert,
field and tz packages.Most applications should not need to import classes from the private packages.

Working with DateTime

Construction

A datetime object is created by using a DateTime constructor. The defaultconstructor is used as follows

DateTime dt = new DateTime();


and creates a datetime object representing the current date and time in millisecondsas determined by the system clock. It is constructed using the ISOcalendar in the default time zone.
To create a datetime object representing a specific date and time, you may use aninitialization string:

DateTime dt = new DateTime("2004-12-13T21:39:45.618-08:00");


The initialization string must be in a format that is compatible with the ISO8601standard.
DateTime also providesotherconstructors to create a specific date and time using a variety of standardfields.
This also permits the use of any calendar and timezone.

JDK Interoperability

The DateTime class has a constructor which takes an Objectas input. In particular this constructor can be passed a JDKDate,JDK
Calendar or JDK GregorianCalendar (It also accepts anISO8601 formatted String, orLong object representing milliseconds). This is one halfof the interoperability with the JDK. The other half of interoperability with JDKis provided
byDateTime methods which return JDK objects.

Thus inter-conversion between Joda DateTime and JDK Datecan be performed as follows

    // from Joda to JDK
DateTime dt = new DateTime(); Date jdkDate = dt.toDate();

// from JDK to Joda
dt = new DateTime(jdkDate);


Similarly, for JDK Calendar:

    // from Joda to JDK
DateTime dt = new DateTime(); Calendar jdkCal = dt.toCalendar(Locale.CHINESE);

// from JDK to Joda
dt = new DateTime(jdkCal);


and JDK GregorianCalendar:

    // from Joda to JDK
DateTime dt = new DateTime(); GregorianCalendar jdkGCal = dt.toGregorianCalendar();

// from JDK to Joda
dt = new DateTime(jdkGCal);


Querying DateTimes

The separation of the calculation of calendar fields (DateTimeField)from the representation of the calendar instant (DateTime) makesfor a powerful and flexible API. The connectionbetween the two is maintained by the property (DateTime.Property)which
provides access to the field.

For instance, the direct way to get the day of week for a particularDateTime, involves calling the method

int iDoW = dt.getDayOfWeek();


where iDoW can take the values (from classDateTimeConstants).

public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
    public static final int THURSDAY = 4;
    public static final int FRIDAY = 5;
    public static final int SATURDAY = 6;
    public static final int SUNDAY = 7;


Accessing fields

The direct methods are fine for simple usage, but more flexibility can be achieved via theproperty/field mechanism. The day of week property is obtained by

DateTime.Property pDoW = dt.dayOfWeek();


which can be used to get richer information about the field, such as

String strST = pDoW.getAsShortText(); // returns "Mon", "Tue", etc.
    String strT = pDoW.getAsText(); // returns "Monday", "Tuesday", etc.


which return short and long name strings (based on the current locale)of the day-of-week. Localized versions of these methods are also available, thus

String strTF = pDoW.getAsText(Locale.FRENCH); // returns "Lundi", etc.


can be used to return the day-of-week name string in French.
Of course, the original integer value of the field is still accessible as

iDoW = pDoW.get();


The property also provides access to other values associated with the fieldsuch as metadata on the minimum and maximum text size, leap status, related durations, etc. For a complete reference, see thedocumentationfor
the base class AbstractReadableInstantFieldProperty
In practice, one would not actually create the intermediate pDoWvariable. The code is easier to read if the methods are called on anonymousintermediate objects. Thus, for example,

strT = dt.dayOfWeek().getAsText();
    iDoW = dt.dayOfWeek().get();


would be written instead of the more indirect code presented earlier.
Note: For the single case of getting the numerical value of a field, we recommendusing the get method on the mainDateTime object as it is more efficient.

iDoW = dt.getDayOfWeek();


Date fields

The DateTime implementation provides a complete list of standardcalendar fields:

dt.getEra();
    dt.getYear();
    dt.getWeekyear();
    dt.getCenturyOfEra();
    dt.getYearOfEra();
    dt.getYearOfCentury();
    dt.getMonthOfYear();
    dt.getWeekOfWeekyear();
    dt.getDayOfYear();
    dt.getDayOfMonth();
    dt.getDayOfWeek();


Each of these also has a corresponding property method, which returns aDateTime.Property binding to the appropriate field, such asyear() ormonthOfYear().The fields represented by these properties behave pretty much as theirnames would
suggest. The precise definitions are available in thefield reference.
As you would expect, all the methods we showed above in the day-of-week examplecan be applied to any of these properties. For example, to extract the standardmonth, day and year fields from a datetime, we can write

String month = dt.monthOfYear().getAsText();
    int maxDay = dt.dayOfMonth().getMaximumValue();
    boolean leapYear = dt.yearOfEra().isLeap();


Time fields

Another set of properties access fields representing intra-day durations fortime calculations. Thus to compute the hours, minutes and seconds of the instantrepresented by aDateTime, we would write

int hour = dt.getHourOfDay();
    int min = dt.getMinuteOfHour();
    int sec = dt.getSecondOfMinute();


Again each of these has a corresponding property method for more complex manipulation.The complete list of time fields can be found in thefield reference.

Manipulating DateTimes

DateTime objects have value semantics, and cannot be modified afterconstruction (they are immutable).Therefore, most simple manipulation of a datetime object involvesconstruction of a new datetime as a modified copy of the original.

WARNING: A common mistake to make with immutable classes is to forget to assignthe result to a variable. Remember that calling an add or set method on animmtable object has no effect on that object - only the result is updated.

Modifying fields

One way to do this is to use methods on properties. Toreturn to our prior example, if we wish to modify thedt objectby changing its day-of-week field to Monday we can do so by using thesetCopy method of the property:

DateTime result = dt.dayOfWeek().setCopy(DateTimeConstants.MONDAY);


Note: If the DateTime object is already set to Monday then the sameobject will be returned.
To add to a date you could use the addToCopy method.

DateTime result = dt.dayOfWeek().addToCopy(3);


DateTime methods

Another means of accomplishing similar calculations is to use methods on theDateTime object itself. Thus we could add 3 days todtdirectly as follows:

DateTime result = dt.plusDays(3);


Using a MutableDateTime

The methods outlined above are suitable for simple calculations involving oneor two fields. In situations where multiple fields need to be modified, it ismore efficient to create a mutable copy of the datetime, modify the copy andfinally create a new value
datetime.

MutableDateTime mdt = dt.toMutableDateTime();
    // perform various calculations on mdt
    ...
    DateTime result = mdt.toDateTime();


MutableDateTime has a number of methods, including standard setters,for directly modifying the datetime.

Changing TimeZone

DateTime comes with support for a couple of common timezonecalculations. For instance, if you want to get the local time in London at thisvery moment, you would do the following

    // get current moment in default time zone
DateTime dt = new DateTime(); // translate to London local time
DateTime dtLondon = dt.withZone(DateTimeZone.forID("Europe/London"));


where DateTimeZone.forID("Europe/London") returns the timezonevalue for London. The resulting valuedtLondon has the same absolutemillisecond time, but a different set of field values.
There is also support for the reverse operation, i.e. to get the datetime (absolutemillisecond) corresponding to the moment when London has the same local time asexists in the default time zonenow. This is done as follows

    // get current moment in default time zone
DateTime dt = new DateTime(); // find the moment when London will have / had the same time
dtLondonSameTime = dt.withZoneRetainFields(DateTimeZone.forID("Europe/London"));


A set of all TimeZone ID strings (such as "Europe/London") may be obtained bycallingDateTimeZone.getAvailableIDs(). A full list of availabletime zones is providedhere.

Changing Chronology

The DateTime class also has one method for changing calendars. Thisallows you to change the calendar for a given moment in time. Thus if you want toget the datetime for the current time, but in the Buddhist Calendar, you would do

    // get current moment in default time zone
DateTime dt = new DateTime(); dt.getYear(); // returns 2004
// change to Buddhist chronology
DateTime dtBuddhist = dt.withChronology(BuddhistChronology.getInstance());
dtBuddhist.getYear(); // returns 2547


where BuddhistChronology.getInstance is a factory method for obtaining aBuddhist chronology.

Input and Output

Reading date time information from external sources which have their own customformat is a frequent requirement for applications that have datetimecomputations. Writing to a custom format is also a common requirement.

Many custom formats can be represented by date-format strings which specifya sequence of calendar fields along with the representation (numeric, name string,etc) and the field length. For example the pattern"yyyy" wouldrepresent a 4 digit year.
Other formats are not so easily represented. Forexample, the pattern"yy" for a two digit year does not uniquelyidentify the century it belongs to. On output, this will not cause problems, butthere is a problem of interpretation on input.

In addition, there are several date/time serialization standards in common usetoday, in particular the ISO8601. These must also be supported by most datetimeapplications.

Joda time supports these different requirements through a flexible architecture.We will now describe the various elements of this architecture.

Formatters

All printing and parsing is performed using a DateTimeFormatter object.Given such an objectfmt, parsing is performed as follows

String strInputDateTime;
    // string is populated with a date time string in some fashion
    ...
    DateTime dt = fmt.parseDateTime(strInputDateTime);


Thus a DateTime object is returned from the parse method of theformatter. Similarly, output is performed as

String strOutputDateTime = fmt.print(dt);


Standard Formatters

Support for standard formats based on ISO8601 is provided by theISODateTimeFormat class. This provides a number of factory methods.

For example, if you wanted to use the ISO standard format for datetime,which isyyyy-MM-dd'T'HH:mm:ss.SSSZZ, you would initializefmt as

DateTimeFormatter fmt = ISODateTimeFormat.dateTime();


You would then use fmt as described above, to read or write datetimeobjects in this format.

Custom Formatters

If you need a custom formatter which can be described in terms ofa format pattern, you can use the factory method provided by theDateTimeFormat class. Thus to get a formatter for a 4 digit year,2 digit month and 2 digit day of month, i.e. a format
of yyyyMMddyou would do

DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMdd");


The pattern string is compatible with JDK date patterns.
You may need to print or parse in a particular Locale.This is achieved by calling thewithLocale method on a formatter,which returns another formatter based on the original.

DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMdd");    DateTimeFormatter frenchFmt = fmt.withLocale(Locale.FRENCH);
DateTimeFormatter germanFmt = fmt.withLocale(Locale.GERMAN);


Formatters are immutable, so the original is not altered by thewithLocale method.

Freaky Formatters

Finally, if you have a format that is not easily represented by a pattern string,Joda Time architecture exposes a builder class that can be used to build a customformatter which is programatically defined. Thus if you wanted a formatter toprint and parse
dates of the form "22-Jan-65", you could do the following:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
            .appendDayOfMonth(2)
            .appendLiteral('-')
            .appendMonthOfYearShortText()
            .appendLiteral('-')
            .appendTwoDigitYear(1956)  // pivot = 1956
            .toFormatter();


Each append method appends a new field to be parsed/printed to thecalling builder and returns a new builder. The finaltoFormatter methodcreates the actual formatter that will be used to print/parse.
What is particularly interesting about this format is the two digit year. Sincethe interpretation of a two digit year is ambiguous, theappendTwoDigitYear takes an extra parameter that defines the 100 yearrange of the two digits, by specifying the
mid point of the range. In this examplethe range will be (1956 - 50) = 1906, to (1956 + 49) = 2005. Thus 04 will be 2004but 07 will be 1907. This kind of conversion is not possible with ordinary formatstrings, highlighting the power of the Joda time formatting
architecture.

Direct access

To simplify the access to the formatter architecture, methods have beenprovided on the datetime classes such as DateTime.

DateTime dt = new DateTime();    String a = dt.toString();
String b = dt.toString("dd:MM:yy");
String c = dt.toString("EEE", Locale.FRENCH);
DateTimeFormatter fmt = ...;
String d = dt.toString(fmt);


Each of the four results demonstrates a different way to use the formatters.Resulta is the standard ISO8601 string for the DateTime.Result
b will output using the pattern 'dd:MM:yy' (note thatpatterns are cached internally).Resultc will output using the pattern 'EEE' in French.Result
d will output using the specified formatter, and is thusthe same asfmt.print(dt).

Advanced features

Change the Current Time

Joda-Time allows you to change the current time.All methods that get the current time are indirected viaDateTimeUtils.This allows the current time to be changed, which can be very useful for testing.

// always return the same time when querying current time
    DateTimeUtils.setCurrentMillisFixed(millis);
    // offset the real time
    DateTimeUtils.setCurrentMillisOffset(millis);


Note that changing the current time this way does not affect the system clock.

Converters

The constructors on each major concrete class in the API take an Objectas a parameter.This is passed to the converter subsystem which is responsible for convertingthe object to one acceptable to Joda-Time.For example, the converters can convert
a JDK Date object to a DateTime.If required, you can add your own converters to those supplied in Joda-Time.

Security

Joda-Time includes hooks into the standard JDK security scheme for sensitive changes.These include changing the time zone handler, changing the current time and changingthe converters.SeeJodaTimePermission for details.

原文链接:http://joda-time.sourceforge.net/userguide.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: