├── docs ├── javadoc │ ├── package-list │ ├── resources │ │ ├── tab.gif │ │ ├── titlebar.gif │ │ ├── background.gif │ │ └── titlebar_end.gif │ ├── allclasses-noframe.html │ ├── allclasses-frame.html │ ├── index.html │ ├── hirondelle │ │ └── date4j │ │ │ ├── package-frame.html │ │ │ ├── doc-files │ │ │ └── VersionHistory.html │ │ │ ├── package-summary.html │ │ │ ├── package-tree.html │ │ │ └── DateTime.Unit.html │ ├── highlight.css │ ├── src-html │ │ └── hirondelle │ │ │ └── date4j │ │ │ ├── TESTAll.html │ │ │ ├── Util.html │ │ │ ├── Examples.html │ │ │ └── DateTimeParser.html │ ├── deprecated-list.html │ ├── constant-values.html │ ├── overview-summary.html │ ├── overview-tree.html │ ├── help-doc.html │ └── serialized-form.html ├── date4j.jar ├── date4j-source.zip ├── images │ └── favicon.ico ├── LICENSE_BSD.txt ├── highlight.css ├── web4j-javadoc.css ├── css │ └── stylesheet11.css └── examples.txt ├── libs └── junit.jar ├── .gitignore ├── MANIFEST.MF ├── CONTRIBUTING.txt ├── classes ├── hirondelle │ └── date4j │ │ ├── TESTAll.java │ │ ├── Util.java │ │ ├── doc-files │ │ └── VersionHistory.html │ │ ├── DateTimeParser.java │ │ ├── Examples.java │ │ ├── DateTimeInterval.java │ │ ├── TESTDateTimeFormatter.java │ │ └── ToStringUtil.java └── overview.html ├── README.md ├── LICENSE.txt ├── highlight.css └── javadoc.css /docs/javadoc/package-list: -------------------------------------------------------------------------------- 1 | hirondelle.date4j 2 | -------------------------------------------------------------------------------- /docs/date4j.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johanley/date4j/HEAD/docs/date4j.jar -------------------------------------------------------------------------------- /libs/junit.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johanley/date4j/HEAD/libs/junit.jar -------------------------------------------------------------------------------- /docs/date4j-source.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johanley/date4j/HEAD/docs/date4j-source.zip -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johanley/date4j/HEAD/docs/images/favicon.ico -------------------------------------------------------------------------------- /docs/javadoc/resources/tab.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johanley/date4j/HEAD/docs/javadoc/resources/tab.gif -------------------------------------------------------------------------------- /docs/javadoc/resources/titlebar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johanley/date4j/HEAD/docs/javadoc/resources/titlebar.gif -------------------------------------------------------------------------------- /docs/javadoc/resources/background.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johanley/date4j/HEAD/docs/javadoc/resources/background.gif -------------------------------------------------------------------------------- /docs/javadoc/resources/titlebar_end.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johanley/date4j/HEAD/docs/javadoc/resources/titlebar_end.gif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Please edit this file to suit your taste 2 | 3 | # Eclipse items 4 | .project 5 | .classpath 6 | .settings/ 7 | bin/ 8 | 9 | # generated binary files 10 | *.class 11 | 12 | # OS Files # 13 | .DS_Store 14 | 15 | # non-public items used by the project owner 16 | private.build.xml 17 | classes/javadocoptions.txt 18 | classes/classes.txt 19 | inherit.gif -------------------------------------------------------------------------------- /MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Ant-Version: Apache Ant 1.6.5 3 | Created-By: 1.5.0_07-b03 (Sun Microsystems Inc.) 4 | Specification-Title: DATE4J 5 | Specification-Version: 1.5.2 6 | Specification-Vendor: Hirondelle Systems 7 | Implementation-Title: DATE4J 8 | Implementation-Version: 1.5.2 9 | Implementation-Vendor: Hirondelle Systems 10 | Implementation-URL: http://www.date4j.net/ 11 | 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.txt: -------------------------------------------------------------------------------- 1 | Must compile with JDK 1.5. (This is important for remaining compatible 2 | with Android.) 3 | 4 | No tabs please. 5 | 6 | UTF-8 is the preferred file encoding. 7 | 8 | Braces like this please { 9 | //indent 2-3 spaces 10 | } 11 | 12 | The project includes junit.jar, version 3.8.1. 13 | That version is a bit stale, but for the sake of uniformity, please 14 | use that version of junit for any new tests, if you create any. 15 | -------------------------------------------------------------------------------- /classes/hirondelle/date4j/TESTAll.java: -------------------------------------------------------------------------------- 1 | package hirondelle.date4j; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestSuite; 5 | 6 | /** Run all JUnit tests. */ 7 | public final class TESTAll { 8 | 9 | public static void main(String args[]) { 10 | String[] testCaseName = { TESTAll.class.getName()}; 11 | junit.textui.TestRunner.main(testCaseName); 12 | } 13 | 14 | public static Test suite ( ) { 15 | TestSuite suite= new TestSuite("All JUnit Tests"); 16 | 17 | suite.addTest(new TestSuite(TESTDateTime.class)); 18 | suite.addTest(new TestSuite(TESTDateTimeFormatter.class)); 19 | suite.addTest(new TestSuite(TESTDateTimeInterval.class)); 20 | 21 | return suite; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /classes/overview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | DATE4J 8 | 9 | 10 | DATE4J is a simple alternative to the standard JDK date classes. 11 | It was created by Hirondelle Systems (John O'Hanley). 12 | 13 |
14 | "Great software requires a fanatical devotion to beauty." 15 |
- Paul Graham
16 |
17 | 18 |

Version History 19 | 20 |

DATE4J is open source software. It's released under a BSD license. 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Date4j is a lightweight replacement for Java's built-in date classes. 2 | 3 | * compiles with JDK 1.5 or greater 4 | * can be used in Android projects 5 | * its public API is essentially a single class (DateTime) 6 | * BSD License 7 | 8 | In 2014, improved date classes were finally added to the JDK. 9 | Those classes render date4j more or less obsolete. 10 | 11 | Documentation is here (the site date4j.net has been shut down): 12 | 13 | https://johanley.github.io/date4j/index.html 14 | 15 | There's still a use case in which date4j is a good resource. 16 | When new languages are created, they all need a way to represent dates and times. 17 | As a starting point, one option is to port date4j to the new language. 18 | Since date4j consists essentially of a single class, this will not be 19 | be an excessively onerous task. 20 | 21 | Date4j contributors: 22 | 23 | * John O'Hanley (main author, Canada) 24 | * Piero Campalani (Italy) 25 | * Jean-Christophe Garnier (CERN - Switzerland) 26 | * Jamie Craane (Netherlands) 27 | * Dan J (USA) 28 | -------------------------------------------------------------------------------- /docs/javadoc/allclasses-noframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | All Classes (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | All Classes 19 |
20 | 21 | 22 | 23 | 30 | 31 |
DateTime 24 |
25 | DateTime.DayOverflow 26 |
27 | DateTime.Unit 28 |
29 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /docs/javadoc/allclasses-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | All Classes (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | All Classes 19 |
20 | 21 | 22 | 23 | 30 | 31 |
DateTime 24 |
25 | DateTime.DayOverflow 26 |
27 | DateTime.Unit 28 |
29 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /docs/javadoc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | DATE4J Javadoc 8 | 9 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | <H2> 28 | Frame Alert</H2> 29 | 30 | <P> 31 | This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. 32 | <BR> 33 | Link to<A HREF="overview-summary.html">Non-frame version.</A> 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/javadoc/hirondelle/date4j/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | hirondelle.date4j (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | hirondelle.date4j 20 | 21 | 22 | 27 | 28 |
23 | Classes  24 | 25 |
26 | DateTime
29 | 30 | 31 | 32 | 33 | 40 | 41 |
34 | Enums  35 | 36 |
37 | DateTime.DayOverflow 38 |
39 | DateTime.Unit
42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2002-2015, Hirondelle Systems 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of Hirondelle Systems nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY HIRONDELLE SYSTEMS ''AS IS'' AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL HIRONDELLE SYSTEMS BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /docs/LICENSE_BSD.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2013 Hirondelle Systems 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of Hirondelle Systems nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY HIRONDELLE SYSTEMS ''AS IS'' AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL HIRONDELLE SYSTEMS BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /highlight.css: -------------------------------------------------------------------------------- 1 | /* Javadoc style sheet */ 2 | .highlight { 3 | background-color: #FFFDE3; 4 | } 5 | 6 | /* syntax highlighting */ 7 | .keyword { 8 | font-weight: bolder; 9 | color: #000080; 10 | } 11 | .literal { 12 | color: blue; 13 | } 14 | .comment { 15 | color: green; 16 | } 17 | 18 | /* Define colors, fonts and other style attributes here to override the defaults */ 19 | 20 | /* Page background color */ 21 | /* body { background-color: #FFFFFF } */ 22 | body { 23 | background-color: rgb(90%, 90%, 90%); 24 | font-family: Verdana, sans-serif; 25 | } 26 | 27 | 28 | /* Table colors */ 29 | .TableHeadingColor { background: #CCCCFF } /* Dark mauve */ 30 | .TableSubHeadingColor { background: #EEEEFF } /* Light mauve */ 31 | .TableRowColor { 32 | background-color: rgb(90%, 90%, 90%); 33 | /* background: #FFFFFF */ 34 | } 35 | 36 | /* Font used in left-hand frame lists */ 37 | .FrameTitleFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 38 | .FrameHeadingFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 39 | .FrameItemFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 40 | 41 | /* Example of smaller, sans-serif font in frames */ 42 | /* .FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */ 43 | 44 | /* Navigation bar fonts and colors */ 45 | .NavBarCell1 { background-color:#EEEEFF;}/* Light mauve */ 46 | .NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */ 47 | .NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;} 48 | .NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;} 49 | 50 | .NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color: rgb(90%, 90%, 90%);} 51 | .NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color: rgb(90%, 90%, 90%);} 52 | 53 | -------------------------------------------------------------------------------- /docs/highlight.css: -------------------------------------------------------------------------------- 1 | /* Javadoc style sheet */ 2 | .highlight { 3 | background-color: #FFFDE3; 4 | } 5 | 6 | /* syntax highlighting */ 7 | .keyword { 8 | font-weight: bolder; 9 | color: #000080; 10 | } 11 | .literal { 12 | color: blue; 13 | } 14 | .comment { 15 | color: green; 16 | } 17 | 18 | /* Define colors, fonts and other style attributes here to override the defaults */ 19 | 20 | /* Page background color */ 21 | /* body { background-color: #FFFFFF } */ 22 | body { 23 | background-color: rgb(90%, 90%, 90%); 24 | font-family: Verdana, sans-serif; 25 | } 26 | 27 | 28 | /* Table colors */ 29 | .TableHeadingColor { background: #CCCCFF } /* Dark mauve */ 30 | .TableSubHeadingColor { background: #EEEEFF } /* Light mauve */ 31 | .TableRowColor { 32 | background-color: rgb(90%, 90%, 90%); 33 | /* background: #FFFFFF */ 34 | } 35 | 36 | /* Font used in left-hand frame lists */ 37 | .FrameTitleFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 38 | .FrameHeadingFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 39 | .FrameItemFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 40 | 41 | /* Example of smaller, sans-serif font in frames */ 42 | /* .FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */ 43 | 44 | /* Navigation bar fonts and colors */ 45 | .NavBarCell1 { background-color:#EEEEFF;}/* Light mauve */ 46 | .NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */ 47 | .NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;} 48 | .NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;} 49 | 50 | .NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color: rgb(90%, 90%, 90%);} 51 | .NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color: rgb(90%, 90%, 90%);} 52 | 53 | -------------------------------------------------------------------------------- /docs/javadoc/highlight.css: -------------------------------------------------------------------------------- 1 | /* Javadoc style sheet */ 2 | .highlight { 3 | background-color: #FFFDE3; 4 | } 5 | 6 | /* syntax highlighting */ 7 | .keyword { 8 | font-weight: bolder; 9 | color: #000080; 10 | } 11 | .literal { 12 | color: blue; 13 | } 14 | .comment { 15 | color: green; 16 | } 17 | 18 | /* Define colors, fonts and other style attributes here to override the defaults */ 19 | 20 | /* Page background color */ 21 | /* body { background-color: #FFFFFF } */ 22 | body { 23 | background-color: rgb(90%, 90%, 90%); 24 | font-family: Verdana, sans-serif; 25 | } 26 | 27 | 28 | /* Table colors */ 29 | .TableHeadingColor { background: #CCCCFF } /* Dark mauve */ 30 | .TableSubHeadingColor { background: #EEEEFF } /* Light mauve */ 31 | .TableRowColor { 32 | background-color: rgb(90%, 90%, 90%); 33 | /* background: #FFFFFF */ 34 | } 35 | 36 | /* Font used in left-hand frame lists */ 37 | .FrameTitleFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 38 | .FrameHeadingFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 39 | .FrameItemFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 40 | 41 | /* Example of smaller, sans-serif font in frames */ 42 | /* .FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */ 43 | 44 | /* Navigation bar fonts and colors */ 45 | .NavBarCell1 { background-color:#EEEEFF;}/* Light mauve */ 46 | .NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */ 47 | .NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;} 48 | .NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;} 49 | 50 | .NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color: rgb(90%, 90%, 90%);} 51 | .NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color: rgb(90%, 90%, 90%);} 52 | 53 | -------------------------------------------------------------------------------- /docs/web4j-javadoc.css: -------------------------------------------------------------------------------- 1 | /* Javadoc style sheet */ 2 | .highlight { 3 | background-color: #FFFDE3; 4 | } 5 | 6 | /* syntax highlighting */ 7 | .keyword { 8 | font-weight: bolder; 9 | color: #000080; 10 | } 11 | .literal { 12 | color: blue; 13 | } 14 | .comment { 15 | color: green; 16 | } 17 | 18 | /* Define colors, fonts and other style attributes here to override the defaults */ 19 | 20 | /* Page background color */ 21 | /* body { background-color: #FFFFFF } */ 22 | body { 23 | background-color: rgb(90%, 90%, 90%); 24 | font-family: Verdana, sans-serif; 25 | } 26 | 27 | /*style of bullets. */ 28 | li { 29 | list-style-type: square; 30 | } 31 | 32 | /* Table colors */ 33 | .TableHeadingColor { background: #CCCCFF } /* Dark mauve */ 34 | .TableSubHeadingColor { background: #EEEEFF } /* Light mauve */ 35 | .TableRowColor { 36 | background-color: rgb(90%, 90%, 90%); 37 | /* background: #FFFFFF */ 38 | } 39 | 40 | /* Font used in left-hand frame lists */ 41 | .FrameTitleFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 42 | .FrameHeadingFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 43 | .FrameItemFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 44 | 45 | /* Example of smaller, sans-serif font in frames */ 46 | /* .FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */ 47 | 48 | /* Navigation bar fonts and colors */ 49 | .NavBarCell1 { background-color:#EEEEFF;}/* Light mauve */ 50 | .NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */ 51 | .NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;} 52 | .NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;} 53 | 54 | .NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color: rgb(90%, 90%, 90%);} 55 | .NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color: rgb(90%, 90%, 90%);} 56 | 57 | -------------------------------------------------------------------------------- /classes/hirondelle/date4j/Util.java: -------------------------------------------------------------------------------- 1 | package hirondelle.date4j; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.logging.Logger; 5 | 6 | final class Util { 7 | 8 | static boolean textHasContent(String aText) { 9 | return (aText != null) && (aText.trim().length() > 0); 10 | } 11 | 12 | static String quote(Object aObject){ 13 | return SINGLE_QUOTE + String.valueOf(aObject) + SINGLE_QUOTE; 14 | } 15 | 16 | static String getArrayAsString(Object aArray){ 17 | final String fSTART_CHAR = "["; 18 | final String fEND_CHAR = "]"; 19 | final String fSEPARATOR = ", "; 20 | final String fNULL = "null"; 21 | 22 | if ( aArray == null ) return fNULL; 23 | checkObjectIsArray(aArray); 24 | 25 | StringBuilder result = new StringBuilder( fSTART_CHAR ); 26 | int length = Array.getLength(aArray); 27 | for ( int idx = 0 ; idx < length ; ++idx ) { 28 | Object item = Array.get(aArray, idx); 29 | if ( isNonNullArray(item) ){ 30 | //recursive call! 31 | result.append( getArrayAsString(item) ); 32 | } 33 | else{ 34 | result.append( item ); 35 | } 36 | if ( ! isLastItem(idx, length) ) { 37 | result.append(fSEPARATOR); 38 | } 39 | } 40 | result.append(fEND_CHAR); 41 | return result.toString(); 42 | } 43 | 44 | static Logger getLogger(Class aClass){ 45 | return Logger.getLogger(aClass.getPackage().getName()); 46 | } 47 | 48 | // PRIVATE 49 | 50 | private static final String SINGLE_QUOTE = "'"; 51 | 52 | private static boolean isNonNullArray(Object aItem){ 53 | return aItem != null && aItem.getClass().isArray(); 54 | } 55 | 56 | private static void checkObjectIsArray(Object aArray){ 57 | if ( ! aArray.getClass().isArray() ) { 58 | throw new IllegalArgumentException("Object is not an array."); 59 | } 60 | } 61 | 62 | private static boolean isLastItem(int aIdx, int aLength){ 63 | return (aIdx == aLength - 1); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /docs/javadoc/src-html/hirondelle/date4j/TESTAll.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TESTAll.java 5 | 6 | 7 | 8 | 9 |

10 | package hirondelle.date4j;
11 | 
12 | import junit.framework.Test;
13 | import junit.framework.TestSuite;
14 | 
15 | /** Run all JUnit tests. */
16 | public final class TESTAll {
17 | 
18 |   public static void main(String args[]) {
19 |     String[] testCaseName = { TESTAll.class.getName()};
20 |     junit.textui.TestRunner.main(testCaseName);
21 |  }
22 |   
23 |   public static Test suite ( ) {
24 |     TestSuite suite= new TestSuite("All JUnit Tests");
25 | 
26 |     suite.addTest(new TestSuite(TESTDateTime.class));
27 |     suite.addTest(new TestSuite(TESTDateTimeFormatter.class));
28 |     suite.addTest(new TestSuite(TESTDateTimeInterval.class));
29 |     
30 |     return suite;
31 |   }
32 | }
33 |  
34 | 
35 | 36 | 37 | -------------------------------------------------------------------------------- /javadoc.css: -------------------------------------------------------------------------------- 1 | /* Javadoc style sheet */ 2 | .highlight { 3 | background-color: #FFFDE3; 4 | } 5 | 6 | /* syntax highlighting */ 7 | .keyword { 8 | font-weight: bolder; 9 | color: #000080; 10 | } 11 | .literal { 12 | color: blue; 13 | } 14 | .comment { 15 | color: green; 16 | } 17 | 18 | /* Define colors, fonts and other style attributes here to override the defaults */ 19 | 20 | /* Page background color */ 21 | /* body { background-color: #FFFFFF } */ 22 | body { 23 | background-color: rgb(90%, 90%, 90%); 24 | font-family: Verdana, sans-serif; 25 | } 26 | 27 | /*style of bullets. */ 28 | li { 29 | list-style-type: square; 30 | } 31 | 32 | .opening-quote{ 33 | margin: 10px; 34 | margin-left: 12.0em; 35 | margin-right: 10px; 36 | margin-top: 10px; 37 | margin-bottom: 10px; 38 | /* background-color:#E5E2D5; */ 39 | border-top: 1px solid #C2BB9E; 40 | border-left: 5px solid #C2BB9E; 41 | border-right: 5px solid #C2BB9E; 42 | border-bottom: 1px solid #C2BB9E; 43 | padding: 10px; 44 | width: 60%; 45 | } 46 | 47 | .author { 48 | font-style: italic; 49 | padding-top: 0em; 50 | margin-top: 0.25em; 51 | text-align: right; 52 | } 53 | 54 | /* Table colors */ 55 | .TableHeadingColor { background: #CCCCFF } /* Dark mauve */ 56 | .TableSubHeadingColor { background: #EEEEFF } /* Light mauve */ 57 | .TableRowColor { 58 | background-color: rgb(90%, 90%, 90%); 59 | /* background: #FFFFFF */ 60 | } 61 | 62 | /* Font used in left-hand frame lists */ 63 | .FrameTitleFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 64 | .FrameHeadingFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 65 | .FrameItemFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } 66 | 67 | /* Example of smaller, sans-serif font in frames */ 68 | /* .FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */ 69 | 70 | /* Navigation bar fonts and colors */ 71 | .NavBarCell1 { background-color:#EEEEFF;}/* Light mauve */ 72 | .NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */ 73 | .NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;} 74 | .NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;} 75 | 76 | .NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color: rgb(90%, 90%, 90%);} 77 | .NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color: rgb(90%, 90%, 90%);} 78 | 79 | -------------------------------------------------------------------------------- /classes/hirondelle/date4j/doc-files/VersionHistory.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | DATE4J Version History 8 | 9 | 18 | 19 | 20 | 21 |

DATE4J Version History

22 | 23 |

date4j.jar version 1.5.1 (Published November 19, 2013)

24 | Bug fix for numSecondsFrom, which failed when only a time portion was being passed. 25 | Thanks to Jamie Craane for the bug report. 26 | 27 |

date4j.jar version 1.5.0 (Published May 18, 2013)

28 | Some additions regarding nanoseconds, and explicit verification of Strings intended for the DateTime(String) constructor. 29 | This release is backwards-compatible. 30 | 31 |

Thanks to Jean-Christophe Garnier for his assistance with this release. 32 | 33 |

Three methods have been added in this release. 34 |

37 | The above method lets you verify explicitly that text will be parseable by DateTime. 38 | 39 |

The remaining two methods form a pair, and let you pass nanosecond values into and out of DateTime: 40 |

44 | 45 | 46 |

date4j.jar version 1.4.0 (Published July 14, 2012)

47 | There's a single change in this release. 48 | The plus and minus methods have been extended to include fractional seconds (nanoseconds). 49 | This change is not backwards compatible. (Sorry about that.) 50 | Existing code which calls these methods will need to add another parameter at the end. 51 | If you don't care about the nanoseconds, just pass a value of 0. 52 | 53 |

Thanks to Piero Campalani for his help with this item. 54 | 55 |

date4j.jar version 1.3.0 (Published May 24, 2012)

56 | There's a single change in this release. The DateTime constructor that takes a String now also accepts a 'T' separating the 57 | date and the time, in addition to accepting a single space as a separator. Two examples of the new syntax: 58 |
59 | 2012-05-24T02:03:04
60 | 2012-05-24T02:03:04.123456789
61 | 
62 | This change is backwards-compatible. This change was added mainly for compatibility with the input type='datetime-local' 63 | defined by HTML5. It allows browser implementations to submit text of the above syntax. 64 | 65 |

date4j.jar version 1.2.0 (Published June 4, 2011)

66 | There are two changes in this release. This release is not backwards compatible. 67 | 68 |

Formatting
69 | The format() methods have changed implementation. 70 | The style 'YYYYMMDD', for example, is now permitted. (This corrects an oversight.) 71 | 72 |

In addition, the text that can be passed to the format methods can now take a much wider range of values. 73 | For example, a valid format String is : 74 |

'Now: YYYY-MM-DD hh:mm:ss'
75 | This text acts like a little template. The preamble 'Now :' is simply echoed, since it contains no formatting symbols. 76 | 77 |

Such free-form text will often need pairs of escape characters '|', to prevent h, m, s, a, f, and so on from being interpreted 78 | as formatting symbols. For example : 79 |

'|The date is:|  YYYY-MM-DD'
80 | 81 |

DateTime.isValidFormatString(String)
82 | This method has been removed. Since the String passed to the format() methods has no restrictions, such a 83 | method no longer makes sense. 84 | 85 |

date4j.jar version 1.1.0 (Published April 13, 2011)

86 | Sole change: the toString method now returns a better result. 87 | 88 |

date4j.jar version 1.0.0 (Published April 30, 2010)

89 | This is the first version of date4j. 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /docs/javadoc/hirondelle/date4j/doc-files/VersionHistory.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | DATE4J Version History 8 | 9 | 18 | 19 | 20 | 21 |

DATE4J Version History

22 | 23 |

date4j.jar version 1.5.1 (Published November 19, 2013)

24 | Bug fix for numSecondsFrom, which failed when only a time portion was being passed. 25 | Thanks to Jamie Craane for the bug report. 26 | 27 |

date4j.jar version 1.5.0 (Published May 18, 2013)

28 | Some additions regarding nanoseconds, and explicit verification of Strings intended for the DateTime(String) constructor. 29 | This release is backwards-compatible. 30 | 31 |

Thanks to Jean-Christophe Garnier for his assistance with this release. 32 | 33 |

Three methods have been added in this release. 34 |

37 | The above method lets you verify explicitly that text will be parseable by DateTime. 38 | 39 |

The remaining two methods form a pair, and let you pass nanosecond values into and out of DateTime: 40 |

44 | 45 | 46 |

date4j.jar version 1.4.0 (Published July 14, 2012)

47 | There's a single change in this release. 48 | The plus and minus methods have been extended to include fractional seconds (nanoseconds). 49 | This change is not backwards compatible. (Sorry about that.) 50 | Existing code which calls these methods will need to add another parameter at the end. 51 | If you don't care about the nanoseconds, just pass a value of 0. 52 | 53 |

Thanks to Piero Campalani for his help with this item. 54 | 55 |

date4j.jar version 1.3.0 (Published May 24, 2012)

56 | There's a single change in this release. The DateTime constructor that takes a String now also accepts a 'T' separating the 57 | date and the time, in addition to accepting a single space as a separator. Two examples of the new syntax: 58 |
59 | 2012-05-24T02:03:04
60 | 2012-05-24T02:03:04.123456789
61 | 
62 | This change is backwards-compatible. This change was added mainly for compatibility with the input type='datetime-local' 63 | defined by HTML5. It allows browser implementations to submit text of the above syntax. 64 | 65 |

date4j.jar version 1.2.0 (Published June 4, 2011)

66 | There are two changes in this release. This release is not backwards compatible. 67 | 68 |

Formatting
69 | The format() methods have changed implementation. 70 | The style 'YYYYMMDD', for example, is now permitted. (This corrects an oversight.) 71 | 72 |

In addition, the text that can be passed to the format methods can now take a much wider range of values. 73 | For example, a valid format String is : 74 |

'Now: YYYY-MM-DD hh:mm:ss'
75 | This text acts like a little template. The preamble 'Now :' is simply echoed, since it contains no formatting symbols. 76 | 77 |

Such free-form text will often need pairs of escape characters '|', to prevent h, m, s, a, f, and so on from being interpreted 78 | as formatting symbols. For example : 79 |

'|The date is:|  YYYY-MM-DD'
80 | 81 |

DateTime.isValidFormatString(String)
82 | This method has been removed. Since the String passed to the format() methods has no restrictions, such a 83 | method no longer makes sense. 84 | 85 |

date4j.jar version 1.1.0 (Published April 13, 2011)

86 | Sole change: the toString method now returns a better result. 87 | 88 |

date4j.jar version 1.0.0 (Published April 30, 2010)

89 | This is the first version of date4j. 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /docs/javadoc/src-html/hirondelle/date4j/Util.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Util.java 5 | 6 | 7 | 8 | 9 |
10 | package hirondelle.date4j;
11 | 
12 | import java.lang.reflect.Array;
13 | import java.util.logging.Logger;
14 | 
15 | final class Util  {
16 | 
17 |   static boolean textHasContent(String aText) {
18 |     return (aText != null) && (aText.trim().length() > 0);
19 |   }
20 |   
21 |   static String quote(Object aObject){
22 |     return SINGLE_QUOTE + String.valueOf(aObject) + SINGLE_QUOTE; 
23 |   }
24 |   
25 |   static String getArrayAsString(Object aArray){
26 |     final String fSTART_CHAR = "[";
27 |     final String fEND_CHAR = "]";
28 |     final String fSEPARATOR = ", ";
29 |     final String fNULL = "null";
30 |     
31 |     if ( aArray == null ) return fNULL;
32 |     checkObjectIsArray(aArray);
33 | 
34 |     StringBuilder result = new StringBuilder( fSTART_CHAR );
35 |     int length = Array.getLength(aArray);
36 |     for ( int idx = 0 ; idx < length ; ++idx ) {
37 |       Object item = Array.get(aArray, idx);
38 |       if ( isNonNullArray(item) ){
39 |         //recursive call!
40 |         result.append( getArrayAsString(item) );
41 |       }
42 |       else{
43 |         result.append( item );
44 |       }
45 |       if ( ! isLastItem(idx, length) ) {
46 |         result.append(fSEPARATOR);
47 |       }
48 |     }
49 |     result.append(fEND_CHAR);
50 |     return result.toString();
51 |   }
52 | 
53 |   static Logger getLogger(Class<?> aClass){
54 |     return Logger.getLogger(aClass.getPackage().getName());  
55 |   }
56 |   
57 |   // PRIVATE
58 |   
59 |   private static final String SINGLE_QUOTE = "'";
60 |   
61 |   private static boolean isNonNullArray(Object aItem){
62 |     return aItem != null && aItem.getClass().isArray();
63 |   }
64 | 
65 |   private static void checkObjectIsArray(Object aArray){
66 |     if ( ! aArray.getClass().isArray() ) {
67 |       throw new IllegalArgumentException("Object is not an array.");
68 |     }
69 |   }
70 | 
71 |   private static boolean isLastItem(int aIdx, int aLength){
72 |     return (aIdx == aLength - 1);
73 |   }
74 |   
75 | }
76 |  
77 | 
78 | 79 | 80 | -------------------------------------------------------------------------------- /docs/javadoc/deprecated-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Deprecated List (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 46 | 49 | 50 | 51 | 52 | 55 | 71 | 72 |
47 | Version 1.5.1 48 |
73 | 74 | 75 | 76 |
77 |
78 |

79 | Deprecated API

80 |
81 |
82 | Contents 84 | 85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 107 | 110 | 111 | 112 | 113 | 116 | 132 | 133 |
108 | Version 1.5.1 109 |
134 | 135 | 136 | 137 |
138 | Copyright Hirondelle Systems. Published November 19, 2013 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/javadoc/constant-values.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Constant Field Values (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 46 | 49 | 50 | 51 | 52 | 55 | 71 | 72 |
47 | Version 1.5.1 48 |
73 | 74 | 75 | 76 |
77 |
78 |

79 | Constant Field Values

80 |
81 |
82 | Contents 84 | 85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 107 | 110 | 111 | 112 | 113 | 116 | 132 | 133 |
108 | Version 1.5.1 109 |
134 | 135 | 136 | 137 |
138 | Copyright Hirondelle Systems. Published November 19, 2013 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/javadoc/overview-summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Overview (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 47 | 50 | 51 | 52 | 53 | 56 | 72 | 73 |
48 | Version 1.5.1 49 |
74 | 75 | 76 | 77 |
78 | DATE4J is a simple alternative to the standard JDK date classes. 79 |

80 | See: 81 |
82 |           Description 83 |

84 | 85 | 86 | 87 | 89 | 90 | 91 | 92 | 93 | 94 |
88 | Packages
hirondelle.date4j 
95 | 96 |

97 |   98 |

99 | DATE4J is a simple alternative to the standard JDK date classes. 100 | It was created by Hirondelle Systems (John O'Hanley). 101 | 102 |

103 | "Great software requires a fanatical devotion to beauty." 104 |
- Paul Graham
105 |
106 | 107 |

Version History 108 | 109 |

DATE4J is open source software. It's released under a BSD license. 110 |

111 | 112 |

113 |


114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 135 | 138 | 139 | 140 | 141 | 144 | 160 | 161 |
136 | Version 1.5.1 137 |
162 | 163 | 164 | 165 |
166 | Copyright Hirondelle Systems. Published November 19, 2013 167 | 168 | 169 | -------------------------------------------------------------------------------- /docs/css/stylesheet11.css: -------------------------------------------------------------------------------- 1 | 2 | /* Color scheme comes first. */ 3 | body { 4 | /* background-color: rgb(191, 191, 191); */ 5 | background-color: rgb(255,255,255); 6 | } 7 | a { 8 | color: rgb(0,100,26); 9 | } 10 | a:hover { 11 | background-color:rgb(164,255,158); 12 | } 13 | a:visited { 14 | color: rgb(0,150,26); 15 | } 16 | .opening-quote { 17 | background-color: rgb(85%, 85%, 85%); 18 | border-top: 1px solid rgb(50%,50%,50%); 19 | border-left: 5px solid rgb(50%,50%,50%); 20 | border-right: 5px solid rgb(50%,50%,50%); 21 | border-bottom: 1px solid rgb(50%,50%,50%); 22 | margin:0em; 23 | padding-top: 1em; 24 | padding-bottom: 1em; 25 | padding-right: 1em; 26 | padding-left: 1em; 27 | } 28 | 29 | .opening-quote{ 30 | margin: 30px; 31 | } 32 | 33 | img.photo { 34 | border-color: rgb(50%,50%,50%); 35 | } 36 | .highlight { 37 | background-color: #ffff66; 38 | } 39 | .sidebar{ 40 | background-color: rgb(85%, 85%, 85%); 41 | border-top: 1px solid rgb(50%,50%,50%); 42 | border-left: 5px solid rgb(50%,50%,50%); 43 | border-right: 5px solid rgb(50%,50%,50%); 44 | border-bottom: 1px solid rgb(50%,50%,50%); 45 | } 46 | 47 | /* End of the color scheme. */ 48 | 49 | 50 | 51 | body { 52 | margin: 1.0em; 53 | padding: 1.0em; 54 | font: 1.0em Verdana, Arial, Helvetica, sans-serif; 55 | } 56 | 57 | a { 58 | font-weight: bold; 59 | text-decoration: none; 60 | } 61 | 62 | /* 63 | Problems : 64 | adds extra line leading. 65 | links have underline that's too low and thick 66 | tt { 67 | line-height:0em; 68 | font-family: monospace; 69 | } 70 | */ 71 | 72 | h2{ 73 | font: bold 20px Verdana, Arial, Helvetica, sans-serif; 74 | border-bottom: 1px solid; 75 | } 76 | 77 | h3{ 78 | font: bold 16px Verdana, Arial, Helvetica, sans-serif; 79 | } 80 | 81 | h4{ 82 | font: bold 16px Verdana, Arial, Helvetica, sans-serif; 83 | } 84 | 85 | blockquote.abstract{ 86 | padding: 0.3em; 87 | } 88 | 89 | ul { 90 | list-style-type: square; 91 | } 92 | 93 | tr { 94 | vertical-align: top 95 | } 96 | 97 | /* 98 | Tables used for user input. 99 | */ 100 | form.user-input table { 101 | background-color: rgb(83%, 83%, 83%); 102 | border-style: solid; 103 | border-width: 2px; 104 | border-color: rgb(45%,45%,45%); 105 | padding: 1.0em; 106 | } 107 | /* improves alignment of form controls */ 108 | form.user-input input { 109 | margin: 0; 110 | } 111 | 112 | 113 | /* 114 | REPORTS 115 | Here, reports are implemented with tables, and refer to any kind of listing. 116 | */ 117 | table.report { 118 | background-color: rgb(83%, 83%, 83%); 119 | border-style: solid; 120 | border-width: 2px; 121 | border-color: rgb(45%,45%,45%); 122 | border-collapse: collapse; 123 | empty-cells: show; 124 | caption-side: bottom; 125 | } 126 | 127 | table.report td, th { 128 | /*white-space: nowrap;*/ 129 | border: 1px ridge rgb(65%,65%,65%); 130 | padding: 0.30em; 131 | } 132 | 133 | /* no underline for sorting links */ 134 | table.report th a { 135 | text-decoration: none; 136 | } 137 | table.report th img { 138 | padding: 0; 139 | margin: 0; 140 | } 141 | 142 | table.report tbody { 143 | border: 1px solid black; 144 | } 145 | /* 146 | Highlighting the row when the cursor hovers above it 147 | increases legibility. 148 | */ 149 | table.report tr:hover { 150 | background-color: #FFFDE3; 151 | } 152 | table.report caption { 153 | font-weight: bold; 154 | text-align: center; 155 | padding: 0.5em; 156 | } 157 | table.report caption:after { 158 | content : " - "; 159 | } 160 | table.report caption:before { 161 | content : " - "; 162 | } 163 | 164 | /* 165 | MESSAGES of various kinds. 166 | */ 167 | .message { 168 | font-weight: bolder; 169 | } 170 | .warning { 171 | font-weight: bolder; 172 | } 173 | .error { 174 | font-weight: bolder; 175 | color: rgb(255,0,0); 176 | } 177 | p.display-messages { 178 | text-align: center; 179 | } 180 | 181 | 182 | img.photo { 183 | margin-top:1.0em; 184 | margin-bottom:1.0em; 185 | margin-left:1.0em; 186 | margin-right:1.0em; 187 | border-style: solid; 188 | border-width: 2px; 189 | } 190 | 191 | img.photo-home { 192 | margin: 0; 193 | border-style: solid; 194 | border-width: 2px; 195 | float: left; 196 | } 197 | 198 | /* The top banner */ 199 | #header{ 200 | text-align:center; 201 | padding-top:0.1em; 202 | } 203 | 204 | 205 | 206 | .loud { 207 | font-size: 150%; 208 | padding: 1.0em; 209 | } 210 | 211 | 212 | #bodycontent{ 213 | margin-left: 0px; 214 | margin-right: 0px; 215 | } 216 | 217 | #nav-menu{ 218 | padding-top:0.5em; 219 | text-align:center; 220 | } 221 | 222 | #nav-menu ul { 223 | list-style-type: none; 224 | padding: 0; 225 | margin: 0; 226 | } 227 | 228 | #nav-menu li { 229 | text-decoration: none; 230 | display: inline; 231 | } 232 | 233 | #nav-menu li a { 234 | padding-left: 7px; 235 | padding-right: 7px; 236 | height: 22px; 237 | width: 75px; 238 | text-decoration: none; 239 | font-weight: bold; 240 | } 241 | 242 | 243 | /* Search form in menu */ 244 | #nav-menu li form { 245 | padding-left: 7px; 246 | padding-top: 6px; 247 | height: 22px; 248 | width: 113px; 249 | font-weight: bold; 250 | } 251 | 252 | 253 | #content{ 254 | /* margin-left: 135px; */ 255 | margin-left: 1em; 256 | padding-top:1px; 257 | } 258 | 259 | #contentdisabled{ 260 | margin: 10px; 261 | padding:10px; 262 | } 263 | 264 | .maincopy a:hover { 265 | text-decoration: underline; 266 | } 267 | 268 | #textcontent{ 269 | height:100%; 270 | padding-left:0; 271 | padding-right:15px; 272 | } 273 | 274 | div.author { 275 | font-style: italic; 276 | padding-top: 0em; 277 | margin-top: 0.25em; 278 | text-align: right; 279 | } 280 | 281 | .sidebar{ 282 | margin: 10px; 283 | padding: 10px; 284 | } 285 | 286 | #footer{ 287 | text-align:center; 288 | height:24px; 289 | padding-top: 10px; 290 | padding-left: 0px; 291 | font: 11px Verdana, Arial, Helvetica, sans-serif; 292 | padding-right: 10px; 293 | border-right-width: 0px; 294 | border-bottom-width: 0px; 295 | border-left-width: 0px; 296 | } 297 | 298 | .small-graphic{ 299 | float:left; 300 | margin-right:0.2em; 301 | } 302 | 303 | /* sometimes footer is too high on page */ 304 | div.spacer { 305 | height: 14.0em; 306 | } 307 | div.smallspacer { 308 | height: 7.0em; 309 | } 310 | div.bigspacer { 311 | height: 30.0em; 312 | } 313 | 314 | 315 | /* Small screens */ 316 | @media all and (max-width: 450px) { 317 | /** Remove margin for small screens. */ 318 | body { 319 | margin: 0.1em; 320 | padding: 0em; 321 | } 322 | } 323 | 324 | /* Styles for print. */ 325 | @media print { 326 | * { 327 | color: black !important; 328 | background: white !important; 329 | } 330 | body { 331 | font-family: "Times New Roman", serif; 332 | font-size: 12pt; 333 | } 334 | a { 335 | text-decoration: none; 336 | } 337 | img.photo { 338 | display: none; 339 | } 340 | div#nav-menu{ 341 | display: none; 342 | } 343 | div#header{ 344 | display: none; 345 | } 346 | } -------------------------------------------------------------------------------- /docs/javadoc/hirondelle/date4j/package-summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | hirondelle.date4j (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 47 | 50 | 51 | 52 | 53 | 56 | 72 | 73 |
48 | Version 1.5.1 49 |
74 | 75 | 76 | 77 |
78 |

79 | Package hirondelle.date4j 80 |

81 | 82 | 83 | 84 | 86 | 87 | 88 | 89 | 90 | 91 |
85 | Class Summary
DateTimeBuilding block class for an immutable date-time, with no time zone.
92 |   93 | 94 |

95 | 96 | 97 | 98 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
99 | Enum Summary
DateTime.DayOverflowPolicy for treating 'day-of-the-month overflow' conditions encountered during some date calculations.
DateTime.UnitThe seven parts of a DateTime object.
110 |   111 | 112 |

113 |

114 |
115 |
116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 137 | 140 | 141 | 142 | 143 | 146 | 162 | 163 |
138 | Version 1.5.1 139 |
164 | 165 | 166 | 167 |
168 | Copyright Hirondelle Systems. Published November 19, 2013 169 | 170 | 171 | -------------------------------------------------------------------------------- /docs/javadoc/overview-tree.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class Hierarchy (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 46 | 49 | 50 | 51 | 52 | 55 | 71 | 72 |
47 | Version 1.5.1 48 |
73 | 74 | 75 | 76 |
77 |
78 |

79 | Hierarchy For All Packages

80 |
81 |
82 |
Package Hierarchies:
hirondelle.date4j
83 |
84 |

85 | Class Hierarchy 86 |

87 | 92 |

93 | Enum Hierarchy 94 |

95 | 102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 124 | 127 | 128 | 129 | 130 | 133 | 149 | 150 |
125 | Version 1.5.1 126 |
151 | 152 | 153 | 154 |
155 | Copyright Hirondelle Systems. Published November 19, 2013 156 | 157 | 158 | -------------------------------------------------------------------------------- /docs/javadoc/hirondelle/date4j/package-tree.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | hirondelle.date4j Class Hierarchy (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 46 | 49 | 50 | 51 | 52 | 55 | 71 | 72 |
47 | Version 1.5.1 48 |
73 | 74 | 75 | 76 |
77 |
78 |

79 | Hierarchy For Package hirondelle.date4j 80 |

81 |
82 |

83 | Class Hierarchy 84 |

85 | 90 |

91 | Enum Hierarchy 92 |

93 | 100 |
101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 122 | 125 | 126 | 127 | 128 | 131 | 147 | 148 |
123 | Version 1.5.1 124 |
149 | 150 | 151 | 152 |
153 | Copyright Hirondelle Systems. Published November 19, 2013 154 | 155 | 156 | -------------------------------------------------------------------------------- /docs/examples.txt: -------------------------------------------------------------------------------- 1 | package hirondelle.date4j; 2 | 3 | import java.util.Locale; 4 | import java.util.TimeZone; 5 | 6 | /** Examples of how to use date4j. */ 7 | public final class Examples { 8 | 9 | /** 10 | Run the examples, and output to the console. 11 | 12 |

Example output when you run this class: 13 |

 14 |    Current date-time in default time zone : 2011-10-24 08:05:59
 15 |    Current date-time in Cairo : 2011-10-24 13:06:00 (Monday)
 16 |    Age of someone born May 16, 1995 is : 16
 17 |    The 3rd Friday of this month is : 2011-10-21
 18 |    Number of days till Christmas : 62
 19 |    90 days from today is : 2012-01-22
 20 |    3 months and 5 days from today is : 2012-01-29
 21 |    Numbers of hours difference between Paris and Perth : 6
 22 |    The number of weeks since Sep 6, 2010 : 59
 23 |    This many seconds till midnight : 57240
 24 |    Output using an ISO format: 2011-10-24T08:06:00
 25 |    The first day of this week is : 2011-10-23
 26 |    The number of years the JDK date-time API has been suctorial : 15
 27 |   
28 | */ 29 | public static void main(String... aArgs){ 30 | Examples examples = new Examples(); 31 | examples.currentDateTime(); 32 | examples.currentDateTimeInCairo(); 33 | examples.ageIfBornOnCertainDate(); 34 | examples.optionsExpiry(); 35 | examples.daysTillChristmas(); 36 | examples.whenIs90DaysFromToday(); 37 | examples.whenIs3Months5DaysFromToday(); 38 | examples.hoursDifferenceBetweenParisAndPerth(); 39 | examples.weeksSinceStart(); 40 | examples.timeTillMidnight(); 41 | examples.imitateISOFormat(); 42 | examples.firstDayOfThisWeek(); 43 | examples.jdkDatesSuctorial(); 44 | } 45 | 46 | // PRIVATE 47 | 48 | private static void log(Object aMsg){ 49 | System.out.println(String.valueOf(aMsg)); 50 | } 51 | 52 | /** What is the current date-time in the JRE's default time zone? */ 53 | private void currentDateTime(){ 54 | DateTime now = DateTime.now(TimeZone.getDefault()); 55 | String result = now.format("YYYY-MM-DD hh:mm:ss"); 56 | log("Current date-time in default time zone : " + result); 57 | } 58 | 59 | /** What is the current date-time in Cairo (include weekday)? */ 60 | private void currentDateTimeInCairo(){ 61 | DateTime now = DateTime.now(TimeZone.getTimeZone("Africa/Cairo")); 62 | String result = now.format("YYYY-MM-DD hh:mm:ss (WWWW)", Locale.getDefault()); 63 | log("Current date-time in Cairo : " + result); 64 | } 65 | 66 | /** What's the age of someone born May 16, 1995? */ 67 | private void ageIfBornOnCertainDate(){ 68 | DateTime today = DateTime.today(TimeZone.getDefault()); 69 | DateTime birthdate = DateTime.forDateOnly(1995, 5, 16); 70 | int age = today.getYear() - birthdate.getYear(); 71 | if(today.getDayOfYear() < birthdate.getDayOfYear()){ 72 | age = age - 1; 73 | } 74 | log("Age of someone born May 16, 1995 is : " + age); 75 | } 76 | 77 | /** Stock options expire on the 3rd Friday of this month. What day of the month is that? */ 78 | private void optionsExpiry(){ 79 | DateTime today = DateTime.today(TimeZone.getDefault()); 80 | DateTime firstOfMonth = today.getStartOfMonth(); 81 | int result = 0; 82 | if (firstOfMonth.getWeekDay() == 7){ 83 | result = 21; 84 | } 85 | else { 86 | result = 21 - firstOfMonth.getWeekDay(); 87 | } 88 | DateTime thirdFriday = DateTime.forDateOnly(firstOfMonth.getYear(), firstOfMonth.getMonth(), result); 89 | log("The 3rd Friday of this month is : " + thirdFriday.format("YYYY-MM-DD")); 90 | } 91 | 92 | /** How many days till the next December 25? */ 93 | private void daysTillChristmas(){ 94 | DateTime today = DateTime.today(TimeZone.getDefault()); 95 | DateTime christmas = DateTime.forDateOnly(today.getYear(), 12, 25); 96 | int result = 0; 97 | if(today.isSameDayAs(christmas)){ 98 | // do nothing 99 | } 100 | else if (today.lt(christmas)){ 101 | result = today.numDaysFrom(christmas); 102 | } 103 | else if (today.gt(christmas)){ 104 | DateTime christmasNextYear = DateTime.forDateOnly(today.getYear() + 1, 12, 25); 105 | result = today.numDaysFrom(christmasNextYear); 106 | } 107 | log("Number of days till Christmas : " + result); 108 | } 109 | 110 | /** What day is 90 days from today? */ 111 | private void whenIs90DaysFromToday(){ 112 | DateTime today = DateTime.today(TimeZone.getDefault()); 113 | log("90 days from today is : " + today.plusDays(90).format("YYYY-MM-DD")); 114 | } 115 | 116 | /** What day is 3 months and 5 days from today? */ 117 | private void whenIs3Months5DaysFromToday(){ 118 | DateTime today = DateTime.today(TimeZone.getDefault()); 119 | DateTime result = today.plus(0,3,5,0,0,0,0,DateTime.DayOverflow.FirstDay); 120 | log("3 months and 5 days from today is : " + result.format("YYYY-MM-DD")); 121 | } 122 | 123 | /** Current number of hours difference between Paris, France and Perth, Australia. */ 124 | private void hoursDifferenceBetweenParisAndPerth(){ 125 | //this assumes the time diff is a whole number of hours; other styles are possible 126 | DateTime paris = DateTime.now(TimeZone.getTimeZone("Europe/Paris")); 127 | DateTime perth = DateTime.now(TimeZone.getTimeZone("Australia/Perth")); 128 | int result = perth.getHour() - paris.getHour(); 129 | if( result < 0 ) { 130 | result = result + 24; 131 | } 132 | log("Numbers of hours difference between Paris and Perth : " + result); 133 | } 134 | 135 | /** How many weeks is it since Sep 6, 2010? */ 136 | private void weeksSinceStart(){ 137 | DateTime today = DateTime.today(TimeZone.getDefault()); 138 | DateTime startOfProject = DateTime.forDateOnly(2010, 9, 6); 139 | int result = today.getWeekIndex() - startOfProject.getWeekIndex(); 140 | log("The number of weeks since Sep 6, 2010 : " + result); 141 | } 142 | 143 | /** How much time till midnight? */ 144 | private void timeTillMidnight(){ 145 | DateTime now = DateTime.now(TimeZone.getDefault()); 146 | DateTime midnight = now.plusDays(1).getStartOfDay(); 147 | long result = now.numSecondsFrom(midnight); 148 | log("This many seconds till midnight : " + result); 149 | } 150 | 151 | /** Format using ISO style. */ 152 | private void imitateISOFormat(){ 153 | DateTime now = DateTime.now(TimeZone.getDefault()); 154 | log("Output using an ISO format: " + now.format("YYYY-MM-DDThh:mm:ss")); 155 | } 156 | 157 | private void firstDayOfThisWeek(){ 158 | DateTime today = DateTime.today(TimeZone.getDefault()); 159 | DateTime firstDayThisWeek = today; //start value 160 | int todaysWeekday = today.getWeekDay(); 161 | int SUNDAY = 1; 162 | if(todaysWeekday > SUNDAY){ 163 | int numDaysFromSunday = todaysWeekday - SUNDAY; 164 | firstDayThisWeek = today.minusDays(numDaysFromSunday); 165 | } 166 | log("The first day of this week is : " + firstDayThisWeek); 167 | } 168 | 169 | /** For how many years has the JDK date-time API been suctorial? */ 170 | private void jdkDatesSuctorial(){ 171 | DateTime today = DateTime.today(TimeZone.getDefault()); 172 | DateTime jdkFirstPublished = DateTime.forDateOnly(1996, 1, 23); 173 | int result = today.getYear() - jdkFirstPublished.getYear(); 174 | log("The number of years the JDK date-time API has been suctorial : " + result); 175 | } 176 | 177 | } -------------------------------------------------------------------------------- /classes/hirondelle/date4j/DateTimeParser.java: -------------------------------------------------------------------------------- 1 | package hirondelle.date4j; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | /** 7 | Convert a date-time from a string into a {@link DateTime}. 8 | The primary use case for this class is converting date-times from a database ResultSet 9 | into a {@link DateTime}. It can also convert an ISO time, having a 'T' separating the date 10 | from the time. 11 | */ 12 | final class DateTimeParser { 13 | 14 | /** 15 | Thrown when the given string cannot be converted into a DateTime, since it doesn't 16 | have a format allowed by this class. 17 | An unchecked exception. 18 | */ 19 | static final class UnknownDateTimeFormat extends RuntimeException { 20 | private static final long serialVersionUID = -7179421566055773208L; 21 | UnknownDateTimeFormat(String aMessage){ super(aMessage); } 22 | UnknownDateTimeFormat(String aMessage, Throwable aEx){ super(aMessage, aEx); } 23 | } 24 | 25 | DateTime parse(String aDateTime) { 26 | if(aDateTime == null){ 27 | throw new NullPointerException("DateTime string is null"); 28 | } 29 | String dateTime = aDateTime.trim(); 30 | Parts parts = splitIntoDateAndTime(dateTime); 31 | if (parts.hasTwoParts()) { 32 | parseDate(parts.datePart); 33 | parseTime(parts.timePart); 34 | } 35 | else if (parts.hasDateOnly()){ 36 | parseDate(parts.datePart); 37 | } 38 | else if (parts.hasTimeOnly()){ 39 | parseTime(parts.timePart); 40 | } 41 | DateTime result = new DateTime(fYear, fMonth, fDay, fHour, fMinute, fSecond, fNanosecond); 42 | return result; 43 | } 44 | 45 | // PRIVATE 46 | 47 | /** 48 | Gross pattern for dates. 49 | Detailed validation is done by DateTime. 50 | The Group index VARIES for y-m-d according to which option is selected 51 | Year: Group 1, 4, 6 52 | Month: Group 2, 5 53 | Day: Group 3 54 | */ 55 | private static final Pattern DATE = Pattern.compile("(\\d{1,4})-(\\d\\d)-(\\d\\d)|(\\d{1,4})-(\\d\\d)|(\\d{1,4})"); 56 | 57 | /** 58 | Gross pattern for times. 59 | Detailed validation is done by DateTime. 60 | The Group index VARIES for h-m-s-f according to which option is selected 61 | Hour: Group 1, 5, 8, 10 62 | Minute: Group 2, 6, 9 63 | Second: Group 3, 7 64 | Microsecond: Group 4 65 | */ 66 | private static final String CL = "\\:"; //colon is a special character 67 | private static final String TT = "(\\d\\d)"; //colon is a special character 68 | private static final String NUM_DIGITS_FOR_FRACTIONAL_SECONDS = "9"; 69 | private static final Integer NUM_DIGITS = Integer.valueOf(NUM_DIGITS_FOR_FRACTIONAL_SECONDS); 70 | private static final Pattern TIME = Pattern.compile("" + 71 | TT+CL+TT+CL+TT+ "\\." + "(\\d{1," + NUM_DIGITS_FOR_FRACTIONAL_SECONDS + "})" + "|" + 72 | TT+CL+TT+CL+TT+ "|" + 73 | TT+CL+TT+ "|" + 74 | TT 75 | ); 76 | 77 | private static final String COLON = ":"; 78 | private static final int THIRD_POSITION = 2; 79 | 80 | private Integer fYear; 81 | private Integer fMonth; 82 | private Integer fDay; 83 | private Integer fHour; 84 | private Integer fMinute; 85 | private Integer fSecond; 86 | private Integer fNanosecond; 87 | 88 | private class Parts { 89 | String datePart; 90 | String timePart; 91 | boolean hasTwoParts(){ 92 | return datePart != null && timePart != null; 93 | } 94 | boolean hasDateOnly(){ 95 | return timePart == null; 96 | } 97 | boolean hasTimeOnly(){ 98 | return datePart == null; 99 | } 100 | } 101 | 102 | /** Date and time can be separated with a single space, or with a 'T' character (case-sensitive). */ 103 | private Parts splitIntoDateAndTime(String aDateTime){ 104 | Parts result = new Parts(); 105 | int dateTimeSeparator = getDateTimeSeparator(aDateTime); 106 | boolean hasDateTimeSeparator = 0 < dateTimeSeparator && dateTimeSeparator < aDateTime.length(); 107 | if (hasDateTimeSeparator){ 108 | result.datePart = aDateTime.substring(0, dateTimeSeparator); 109 | result.timePart = aDateTime.substring(dateTimeSeparator+1); 110 | } 111 | else if(hasColonInThirdPlace(aDateTime)){ 112 | result.timePart = aDateTime; 113 | } 114 | else { 115 | result.datePart = aDateTime; 116 | } 117 | return result; 118 | } 119 | 120 | /** Return the index of a space character, or of a 'T' character. If not found, return -1.*/ 121 | int getDateTimeSeparator(String aDateTime){ 122 | String SPACE = " "; 123 | int NOT_FOUND = -1; 124 | int result = NOT_FOUND; 125 | result = aDateTime.indexOf(SPACE); 126 | if(result == NOT_FOUND){ 127 | result = aDateTime.indexOf("T"); 128 | } 129 | return result; 130 | } 131 | 132 | private boolean hasColonInThirdPlace(String aDateTime){ 133 | boolean result = false; 134 | if(aDateTime.length() >= THIRD_POSITION){ 135 | result = COLON.equals(aDateTime.substring(THIRD_POSITION,THIRD_POSITION+1)); 136 | } 137 | return result; 138 | } 139 | 140 | private void parseDate(String aDate) { 141 | Matcher matcher = DATE.matcher(aDate); 142 | if (matcher.matches()){ 143 | String year = getGroup(matcher, 1, 4, 6); 144 | if(year !=null ){ 145 | fYear = Integer.valueOf(year); 146 | } 147 | String month = getGroup(matcher, 2, 5); 148 | if(month !=null ){ 149 | fMonth = Integer.valueOf(month); 150 | } 151 | String day = getGroup(matcher, 3); 152 | if(day !=null ){ 153 | fDay = Integer.valueOf(day); 154 | } 155 | } 156 | else { 157 | throw new DateTimeParser.UnknownDateTimeFormat("Unexpected format for date:" + aDate); 158 | } 159 | } 160 | 161 | private String getGroup(Matcher aMatcher, int... aGroupIds){ 162 | String result = null; 163 | for(int id: aGroupIds){ 164 | result = aMatcher.group(id); 165 | if(result!=null) break; 166 | } 167 | return result; 168 | } 169 | 170 | private void parseTime(String aTime) { 171 | Matcher matcher = TIME.matcher(aTime); 172 | if (matcher.matches()){ 173 | String hour = getGroup(matcher, 1, 5, 8, 10); 174 | if(hour !=null ){ 175 | fHour = Integer.valueOf(hour); 176 | } 177 | String minute = getGroup(matcher, 2, 6, 9); 178 | if(minute !=null ){ 179 | fMinute = Integer.valueOf(minute); 180 | } 181 | String second = getGroup(matcher, 3, 7); 182 | if(second !=null ){ 183 | fSecond = Integer.valueOf(second); 184 | } 185 | String decimalSeconds = getGroup(matcher, 4); 186 | if(decimalSeconds !=null ){ 187 | fNanosecond = Integer.valueOf(convertToNanoseconds(decimalSeconds)); 188 | } 189 | } 190 | else { 191 | throw new DateTimeParser.UnknownDateTimeFormat("Unexpected format for time:" + aTime); 192 | } 193 | } 194 | 195 | /** 196 | Convert any number of decimals (1..9) into the form it would have taken if nanos had been used, 197 | by adding any 0's to the right side. 198 | */ 199 | private String convertToNanoseconds(String aDecimalSeconds){ 200 | StringBuilder result = new StringBuilder(aDecimalSeconds); 201 | while( result.length( ) < NUM_DIGITS ){ 202 | result.append("0"); 203 | } 204 | return result.toString(); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /classes/hirondelle/date4j/Examples.java: -------------------------------------------------------------------------------- 1 | package hirondelle.date4j; 2 | 3 | import java.util.Locale; 4 | import java.util.TimeZone; 5 | 6 | /** Examples of how to use date4j. */ 7 | public final class Examples { 8 | 9 | /** 10 | Run the examples, and output to the console. 11 | 12 |

Example output when you run this class: 13 |

 14 |    Current date-time in default time zone : 2011-10-24 08:05:59
 15 |    Current date-time in Cairo : 2011-10-24 13:06:00 (Monday)
 16 |    Age of someone born May 16, 1995 is : 16
 17 |    The 3rd Friday of this month is : 2011-10-21
 18 |    Number of days till Christmas : 62
 19 |    90 days from today is : 2012-01-22
 20 |    3 months and 5 days from today is : 2012-01-29
 21 |    Numbers of hours difference between Paris and Perth : 6
 22 |    The number of weeks since Sep 6, 2010 : 59
 23 |    This many seconds till midnight : 57240
 24 |    Output using an ISO format: 2011-10-24T08:06:00
 25 |    The first day of this week is : 2011-10-23
 26 |    The number of years the JDK date-time API has been suctorial : 15
 27 |   
28 | */ 29 | public static void main(String... aArgs){ 30 | Examples examples = new Examples(); 31 | examples.currentDateTime(); 32 | examples.currentDateTimeInCairo(); 33 | examples.ageIfBornOnCertainDate(); 34 | examples.optionsExpiry(); 35 | examples.daysTillChristmas(); 36 | examples.whenIs90DaysFromToday(); 37 | examples.whenIs3Months5DaysFromToday(); 38 | examples.hoursDifferenceBetweenParisAndPerth(); 39 | examples.weeksSinceStart(); 40 | examples.timeTillMidnight(); 41 | examples.imitateISOFormat(); 42 | examples.firstDayOfThisWeek(); 43 | examples.jdkDatesSuctorial(); 44 | } 45 | 46 | // PRIVATE 47 | 48 | private static void log(Object aMsg){ 49 | System.out.println(String.valueOf(aMsg)); 50 | } 51 | 52 | /** What is the current date-time in the JRE's default time zone? */ 53 | private void currentDateTime(){ 54 | DateTime now = DateTime.now(TimeZone.getDefault()); 55 | String result = now.format("YYYY-MM-DD hh:mm:ss"); 56 | log("Current date-time in default time zone : " + result); 57 | } 58 | 59 | /** What is the current date-time in Cairo (include weekday)? */ 60 | private void currentDateTimeInCairo(){ 61 | DateTime now = DateTime.now(TimeZone.getTimeZone("Africa/Cairo")); 62 | String result = now.format("YYYY-MM-DD hh:mm:ss (WWWW)", Locale.getDefault()); 63 | log("Current date-time in Cairo : " + result); 64 | } 65 | 66 | /** What's the age of someone born May 16, 1995? */ 67 | private void ageIfBornOnCertainDate(){ 68 | DateTime today = DateTime.today(TimeZone.getDefault()); 69 | DateTime birthdate = DateTime.forDateOnly(1995, 5, 16); 70 | int age = today.getYear() - birthdate.getYear(); 71 | if(today.getDayOfYear() < birthdate.getDayOfYear()){ 72 | age = age - 1; 73 | } 74 | log("Age of someone born May 16, 1995 is : " + age); 75 | } 76 | 77 | /** Stock options expire on the 3rd Friday of this month. What day of the month is that? */ 78 | private void optionsExpiry(){ 79 | DateTime today = DateTime.today(TimeZone.getDefault()); 80 | DateTime firstOfMonth = today.getStartOfMonth(); 81 | int result = 0; 82 | if (firstOfMonth.getWeekDay() == 7){ 83 | result = 21; 84 | } 85 | else { 86 | result = 21 - firstOfMonth.getWeekDay(); 87 | } 88 | DateTime thirdFriday = DateTime.forDateOnly(firstOfMonth.getYear(), firstOfMonth.getMonth(), result); 89 | log("The 3rd Friday of this month is : " + thirdFriday.format("YYYY-MM-DD")); 90 | } 91 | 92 | /** How many days till the next December 25? */ 93 | private void daysTillChristmas(){ 94 | DateTime today = DateTime.today(TimeZone.getDefault()); 95 | DateTime christmas = DateTime.forDateOnly(today.getYear(), 12, 25); 96 | int result = 0; 97 | if(today.isSameDayAs(christmas)){ 98 | // do nothing 99 | } 100 | else if (today.lt(christmas)){ 101 | result = today.numDaysFrom(christmas); 102 | } 103 | else if (today.gt(christmas)){ 104 | DateTime christmasNextYear = DateTime.forDateOnly(today.getYear() + 1, 12, 25); 105 | result = today.numDaysFrom(christmasNextYear); 106 | } 107 | log("Number of days till Christmas : " + result); 108 | } 109 | 110 | /** What day is 90 days from today? */ 111 | private void whenIs90DaysFromToday(){ 112 | DateTime today = DateTime.today(TimeZone.getDefault()); 113 | log("90 days from today is : " + today.plusDays(90).format("YYYY-MM-DD")); 114 | } 115 | 116 | /** What day is 3 months and 5 days from today? */ 117 | private void whenIs3Months5DaysFromToday(){ 118 | DateTime today = DateTime.today(TimeZone.getDefault()); 119 | DateTime result = today.plus(0,3,5,0,0,0,0,DateTime.DayOverflow.FirstDay); 120 | log("3 months and 5 days from today is : " + result.format("YYYY-MM-DD")); 121 | } 122 | 123 | /** Current number of hours difference between Paris, France and Perth, Australia. */ 124 | private void hoursDifferenceBetweenParisAndPerth(){ 125 | //this assumes the time diff is a whole number of hours; other styles are possible 126 | DateTime paris = DateTime.now(TimeZone.getTimeZone("Europe/Paris")); 127 | DateTime perth = DateTime.now(TimeZone.getTimeZone("Australia/Perth")); 128 | int result = perth.getHour() - paris.getHour(); 129 | if( result < 0 ) { 130 | result = result + 24; 131 | } 132 | log("Numbers of hours difference between Paris and Perth : " + result); 133 | } 134 | 135 | /** How many weeks is it since Sep 6, 2010? */ 136 | private void weeksSinceStart(){ 137 | DateTime today = DateTime.today(TimeZone.getDefault()); 138 | DateTime startOfProject = DateTime.forDateOnly(2010, 9, 6); 139 | int result = today.getWeekIndex() - startOfProject.getWeekIndex(); 140 | log("The number of weeks since Sep 6, 2010 : " + result); 141 | } 142 | 143 | /** How much time till midnight? */ 144 | private void timeTillMidnight(){ 145 | DateTime now = DateTime.now(TimeZone.getDefault()); 146 | DateTime midnight = now.plusDays(1).getStartOfDay(); 147 | long result = now.numSecondsFrom(midnight); 148 | log("This many seconds till midnight : " + result); 149 | } 150 | 151 | /** Format using ISO style. */ 152 | private void imitateISOFormat(){ 153 | DateTime now = DateTime.now(TimeZone.getDefault()); 154 | log("Output using an ISO format: " + now.format("YYYY-MM-DDThh:mm:ss")); 155 | } 156 | 157 | private void firstDayOfThisWeek(){ 158 | DateTime today = DateTime.today(TimeZone.getDefault()); 159 | DateTime firstDayThisWeek = today; //start value 160 | int todaysWeekday = today.getWeekDay(); 161 | int SUNDAY = 1; 162 | if(todaysWeekday > SUNDAY){ 163 | int numDaysFromSunday = todaysWeekday - SUNDAY; 164 | firstDayThisWeek = today.minusDays(numDaysFromSunday); 165 | } 166 | log("The first day of this week is : " + firstDayThisWeek); 167 | } 168 | 169 | /** For how many years has the JDK date-time API been suctorial? */ 170 | private void jdkDatesSuctorial(){ 171 | DateTime today = DateTime.today(TimeZone.getDefault()); 172 | DateTime jdkFirstPublished = DateTime.forDateOnly(1996, 1, 23); 173 | int result = today.getYear() - jdkFirstPublished.getYear(); 174 | log("The number of years the JDK date-time API has been suctorial : " + result); 175 | } 176 | 177 | } -------------------------------------------------------------------------------- /docs/javadoc/help-doc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | API Help (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 46 | 49 | 50 | 51 | 52 | 55 | 71 | 72 |
47 | Version 1.5.1 48 |
73 | 74 | 75 | 76 |
77 |
78 |

79 | How This API Document Is Organized

80 |
81 | This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.

82 | Overview

83 |
84 | 85 |

86 | The Overview page is the front page of this API document and provides a list of all packages with a summary for each. This page can also contain an overall description of the set of packages.

87 |

88 | Package

89 |
90 | 91 |

92 | Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain four categories:

94 |
95 |

96 | Class/Interface

97 |
98 | 99 |

100 | Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:

106 | Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.
107 | 108 |

109 | Annotation Type

110 |
111 | 112 |

113 | Each annotation type has its own separate page with the following sections:

115 |
116 | 117 |

118 | Enum

119 |
120 | 121 |

122 | Each enum has its own separate page with the following sections:

124 |
125 |

126 | Tree (Class Hierarchy)

127 |
128 | There is a Class Hierarchy page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with java.lang.Object. The interfaces do not inherit from java.lang.Object. 130 |
131 |

132 | Deprecated API

133 |
134 | The Deprecated API page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.
135 |

136 | Index

137 |
138 | The Index contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.
139 |

140 | Prev/Next

141 | These links take you to the next or previous class, interface, package, or related page.

142 | Frames/No Frames

143 | These links show and hide the HTML frames. All pages are available with or without frames. 144 |

145 |

146 | Serialized Form

147 | Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description. 148 |

149 |

150 | Constant Field Values

151 | The Constant Field Values page lists the static final fields and their values. 152 |

153 | 154 | 155 | This help file applies to API documentation generated using the standard doclet. 156 | 157 |
158 |


159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 180 | 183 | 184 | 185 | 186 | 189 | 205 | 206 |
181 | Version 1.5.1 182 |
207 | 208 | 209 | 210 |
211 | Copyright Hirondelle Systems. Published November 19, 2013 212 | 213 | 214 | -------------------------------------------------------------------------------- /classes/hirondelle/date4j/DateTimeInterval.java: -------------------------------------------------------------------------------- 1 | package hirondelle.date4j; 2 | 3 | import hirondelle.date4j.DateTime.DayOverflow; 4 | import hirondelle.date4j.DateTime.Unit; 5 | 6 | /** 7 | Helper class for adding intervals of time. 8 | The mental model of this class is similar to that of a car's odometer. 9 | */ 10 | final class DateTimeInterval { 11 | 12 | /** Constructor. */ 13 | DateTimeInterval(DateTime aFrom, DayOverflow aMonthOverflow){ 14 | fFrom = aFrom; 15 | checkUnits(); 16 | fYear = fFrom.getYear() == null ? 1 : fFrom.getYear(); 17 | fMonth = fFrom.getMonth() == null ? 1 : fFrom.getMonth(); 18 | fDay = fFrom.getDay() == null ? 1 : fFrom.getDay(); 19 | fHour = fFrom.getHour() == null ? 0 : fFrom.getHour(); 20 | fMinute = fFrom.getMinute() == null ? 0 : fFrom.getMinute(); 21 | fSecond = fFrom.getSecond() == null ? 0 : fFrom.getSecond(); 22 | fNanosecond = fFrom.getNanoseconds() == null ? 0 : fFrom.getNanoseconds(); 23 | fDayOverflow = aMonthOverflow; 24 | } 25 | 26 | DateTime plus(int aYear, int aMonth, int aDay, int aHour, int aMinute, int aSecond, int aNanosecond){ 27 | return plusOrMinus(PLUS, aYear, aMonth, aDay, aHour, aMinute, aSecond, aNanosecond); 28 | } 29 | 30 | DateTime minus(int aYear, int aMonth, int aDay, int aHour, int aMinute, int aSecond, int aNanosecond){ 31 | return plusOrMinus(MINUS, aYear, aMonth, aDay, aHour, aMinute, aSecond, aNanosecond); 32 | } 33 | 34 | // PRIVATE 35 | 36 | //the base date to which the interval is calculated 37 | private final DateTime fFrom; 38 | 39 | private boolean fIsPlus; 40 | private DateTime.DayOverflow fDayOverflow; 41 | 42 | //the various increments 43 | private int fYearIncr; 44 | private int fMonthIncr; 45 | private int fDayIncr; 46 | private int fHourIncr; 47 | private int fMinuteIncr; 48 | private int fSecondIncr; 49 | private int fNanosecondIncr; 50 | 51 | //work area for the final result - starts off with values from base date fFrom 52 | private Integer fYear; 53 | private Integer fMonth; 54 | private Integer fDay; 55 | private Integer fHour; 56 | private Integer fMinute; 57 | private Integer fSecond; 58 | private Integer fNanosecond; 59 | 60 | private static final int MIN = 0; 61 | private static final int MAX = 9999; 62 | private static final int MIN_NANOS = 0; 63 | private static final int MAX_NANOS = 999999999; 64 | private static final boolean PLUS = true; 65 | private static final boolean MINUS = false; 66 | 67 | private void checkUnits(){ 68 | boolean success = false; 69 | if(fFrom.unitsAllPresent(Unit.YEAR, Unit.MONTH, Unit.DAY, Unit.HOUR, Unit.MINUTE, Unit.SECOND) ){ 70 | success = true; 71 | } 72 | else if( fFrom.unitsAllPresent(Unit.YEAR, Unit.MONTH, Unit.DAY) && fFrom.unitsAllAbsent(Unit.HOUR, Unit.MINUTE, Unit.SECOND) ){ 73 | success = true; 74 | } 75 | else if ( fFrom.unitsAllAbsent(Unit.YEAR, Unit.MONTH, Unit.DAY) && fFrom.unitsAllPresent(Unit.HOUR, Unit.MINUTE, Unit.SECOND) ){ 76 | success = true; 77 | } 78 | else { 79 | success = false; 80 | } 81 | if(! success ){ 82 | throw new IllegalArgumentException("For interval calculations, DateTime must have year-month-day, or hour-minute-second, or both."); 83 | } 84 | } 85 | 86 | private DateTime plusOrMinus(boolean aIsPlus, Integer aYear, Integer aMonth, Integer aDay, Integer aHour, Integer aMinute, Integer aSecond, Integer aNanosecond){ 87 | fIsPlus = aIsPlus; 88 | fYearIncr = aYear; 89 | fMonthIncr = aMonth; 90 | fDayIncr = aDay; 91 | fHourIncr = aHour; 92 | fMinuteIncr = aMinute; 93 | fSecondIncr = aSecond; 94 | fNanosecondIncr = aNanosecond; 95 | 96 | checkRange(fYearIncr, "Year"); 97 | checkRange(fMonthIncr, "Month"); 98 | checkRange(fDayIncr, "Day"); 99 | checkRange(fHourIncr, "Hour"); 100 | checkRange(fMinuteIncr, "Minute"); 101 | checkRange(fSecondIncr, "Second"); 102 | checkRangeNanos(fNanosecondIncr); 103 | 104 | changeYear(); 105 | changeMonth(); 106 | handleMonthOverflow(); 107 | changeDay(); 108 | changeHour(); 109 | changeMinute(); 110 | changeSecond(); 111 | changeNanosecond(); 112 | 113 | return new DateTime(fYear, fMonth, fDay, fHour, fMinute, fSecond, fNanosecond); 114 | } 115 | 116 | private void checkRange(Integer aValue, String aName) { 117 | if ( aValue < MIN || aValue > MAX ) { 118 | throw new IllegalArgumentException(aName + " is not in the range " + MIN + ".." + MAX); 119 | } 120 | } 121 | 122 | private void checkRangeNanos(Integer aValue) { 123 | if ( aValue < MIN_NANOS || aValue > MAX_NANOS ) { 124 | throw new IllegalArgumentException("Nanosecond interval is not in the range " + MIN_NANOS + ".." + MAX_NANOS); 125 | } 126 | } 127 | 128 | private void changeYear(){ 129 | if(fIsPlus){ 130 | fYear = fYear + fYearIncr; 131 | } 132 | else { 133 | fYear = fFrom.getYear() - fYearIncr; 134 | } 135 | //the DateTime ctor will check the range of the year 136 | } 137 | 138 | private void changeMonth(){ 139 | int count = 0; 140 | while (count < fMonthIncr){ 141 | stepMonth(); 142 | count++; 143 | } 144 | } 145 | 146 | private void changeDay(){ 147 | int count = 0; 148 | while (count < fDayIncr){ 149 | stepDay(); 150 | count++; 151 | } 152 | } 153 | 154 | private void changeHour(){ 155 | int count = 0; 156 | while (count < fHourIncr){ 157 | stepHour(); 158 | count++; 159 | } 160 | } 161 | 162 | private void changeMinute(){ 163 | int count = 0; 164 | while (count < fMinuteIncr){ 165 | stepMinute(); 166 | count++; 167 | } 168 | } 169 | 170 | private void changeSecond(){ 171 | int count = 0; 172 | while (count < fSecondIncr){ 173 | stepSecond(); 174 | count++; 175 | } 176 | } 177 | 178 | /** 179 | Nanos are different from other items. They don't cycle one step at a time. 180 | They are just added. If they under/over flow, then extra math is performed. 181 | They don't over/under by more than 1 second, since the size of the increment is limited. 182 | */ 183 | private void changeNanosecond(){ 184 | if (fIsPlus){ 185 | fNanosecond = fNanosecond + fNanosecondIncr; 186 | } 187 | else { 188 | fNanosecond = fNanosecond - fNanosecondIncr; 189 | } 190 | if(fNanosecond > MAX_NANOS){ 191 | stepSecond(); 192 | fNanosecond = fNanosecond - MAX_NANOS - 1; 193 | } 194 | else if (fNanosecond < MIN_NANOS){ 195 | stepSecond(); 196 | fNanosecond = MAX_NANOS + fNanosecond + 1; 197 | } 198 | } 199 | 200 | private void stepYear() { 201 | if(fIsPlus) { 202 | fYear = fYear + 1; 203 | } 204 | else { 205 | fYear = fYear - 1; 206 | } 207 | } 208 | 209 | private void stepMonth() { 210 | if(fIsPlus){ 211 | fMonth = fMonth + 1; 212 | } 213 | else { 214 | fMonth = fMonth - 1; 215 | } 216 | if(fMonth > 12) { 217 | fMonth = 1; 218 | stepYear(); 219 | } 220 | else if(fMonth < 1){ 221 | fMonth = 12; 222 | stepYear(); 223 | } 224 | } 225 | 226 | private void stepDay() { 227 | if(fIsPlus){ 228 | fDay = fDay + 1; 229 | } 230 | else { 231 | fDay = fDay - 1; 232 | } 233 | if(fDay > numDaysInMonth()){ 234 | fDay = 1; 235 | stepMonth(); 236 | } 237 | else if (fDay < 1){ 238 | fDay = numDaysInPreviousMonth(); 239 | stepMonth(); 240 | } 241 | } 242 | 243 | private int numDaysInMonth(){ 244 | return DateTime.getNumDaysInMonth(fYear, fMonth); 245 | } 246 | 247 | private int numDaysInPreviousMonth(){ 248 | int result = 0; 249 | if(fMonth > 1) { 250 | result = DateTime.getNumDaysInMonth(fYear, fMonth - 1); 251 | } 252 | else { 253 | result = DateTime.getNumDaysInMonth(fYear - 1 , 12); 254 | } 255 | return result; 256 | } 257 | 258 | private void stepHour() { 259 | if(fIsPlus){ 260 | fHour = fHour + 1; 261 | } 262 | else { 263 | fHour = fHour - 1; 264 | } 265 | if(fHour > 23){ 266 | fHour = 0; 267 | stepDay(); 268 | } 269 | else if (fHour < 0){ 270 | fHour = 23; 271 | stepDay(); 272 | } 273 | } 274 | 275 | private void stepMinute() { 276 | if(fIsPlus){ 277 | fMinute = fMinute + 1; 278 | } 279 | else { 280 | fMinute = fMinute - 1; 281 | } 282 | if(fMinute > 59){ 283 | fMinute = 0; 284 | stepHour(); 285 | } 286 | else if (fMinute < 0){ 287 | fMinute = 59; 288 | stepHour(); 289 | } 290 | } 291 | 292 | private void stepSecond() { 293 | if(fIsPlus){ 294 | fSecond = fSecond + 1; 295 | } 296 | else { 297 | fSecond = fSecond - 1; 298 | } 299 | if (fSecond > 59){ 300 | fSecond = 0; 301 | stepMinute(); 302 | } 303 | else if (fSecond < 0){ 304 | fSecond = 59; 305 | stepMinute(); 306 | } 307 | } 308 | 309 | private void handleMonthOverflow(){ 310 | int daysInMonth = numDaysInMonth(); 311 | if( fDay > daysInMonth ){ 312 | if(DayOverflow.Abort == fDayOverflow) { 313 | throw new RuntimeException( 314 | "Day Overflow: Year:" + fYear + " Month:" + fMonth + " has " + daysInMonth + " days, but day has value:" + fDay + 315 | " To avoid these exceptions, please specify a different DayOverflow policy." 316 | ); 317 | } 318 | else if (DayOverflow.FirstDay == fDayOverflow) { 319 | fDay = 1; 320 | nextMonth(); 321 | } 322 | else if (DayOverflow.LastDay == fDayOverflow) { 323 | fDay = daysInMonth; 324 | } 325 | else if (DayOverflow.Spillover == fDayOverflow) { 326 | int overflowAmount = fDay - daysInMonth; 327 | fDay = overflowAmount; 328 | nextMonth(); 329 | } 330 | } 331 | } 332 | 333 | /** 334 | For day-of-the-month overflow cases, the month is never decremented; it either stays the same, 335 | or is incremented. 336 | */ 337 | private void nextMonth(){ 338 | fMonth = fMonth + 1; 339 | if(fMonth > 12) { 340 | fMonth = 1; 341 | fYear = fYear + 1; 342 | } 343 | } 344 | 345 | } 346 | -------------------------------------------------------------------------------- /classes/hirondelle/date4j/TESTDateTimeFormatter.java: -------------------------------------------------------------------------------- 1 | package hirondelle.date4j; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Arrays; 6 | import java.util.Date; 7 | import java.util.List; 8 | import java.util.Locale; 9 | 10 | import junit.framework.TestCase; 11 | 12 | /** JUnit tests. */ 13 | public final class TESTDateTimeFormatter extends TestCase { 14 | 15 | /** Run the test cases. */ 16 | public static void main(String args[]) { 17 | String[] testCaseName = { TESTDateTimeFormatter.class.getName() }; 18 | junit.textui.TestRunner.main(testCaseName); 19 | } 20 | 21 | public TESTDateTimeFormatter(String aName) { 22 | super(aName); 23 | } 24 | 25 | // TEST CASES // 26 | 27 | public void testSpeed(){ 28 | //.046 29 | testDate(SUCCESS, "2009-10-28 01:59:01", "YYYY-MM-DD h12:mm:ss", "2009-10-28 1:59:01"); 30 | } 31 | 32 | public void testSpeedJDK() throws ParseException { 33 | String dateTime = "2009-10-28 01:59:01"; 34 | //.063 - slower than my classes - at least in this simple test 35 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); 36 | Date result = format.parse(dateTime); 37 | String dateResurrected = format.format(result); 38 | } 39 | 40 | public void testDate(){ 41 | testDate(SUCCESS, "2009-10-28", "YYYY-MM-DD", "2009-10-28"); 42 | testDate(SUCCESS, "2009-01-28", "YYYY-MM-DD", "2009-01-28"); 43 | testDate(SUCCESS, "2009-12-01", "YYYY-MM-DD", "2009-12-01"); 44 | testDate(SUCCESS, "2009-01-01", "YYYY-MM-DD", "2009-01-01"); 45 | 46 | testDate(SUCCESS, "2009-10-28", "YYYY-M-D", "2009-10-28"); 47 | testDate(SUCCESS, "2009-10-03", "YYYY-M-D", "2009-10-3"); 48 | testDate(SUCCESS, "2009-05-28", "YYYY-M-D", "2009-5-28"); 49 | 50 | testDate(SUCCESS, "2009-10-28", "YYYY-MM-D", "2009-10-28"); 51 | testDate(SUCCESS, "2009-10-03", "YYYY-MM-D", "2009-10-3"); 52 | testDate(SUCCESS, "2009-05-28", "YYYY-MM-D", "2009-05-28"); 53 | 54 | testDate(SUCCESS, "2009-10-28", "YYYY-M-DD", "2009-10-28"); 55 | testDate(SUCCESS, "2009-10-03", "YYYY-M-DD", "2009-10-03"); 56 | testDate(SUCCESS, "2009-05-28", "YYYY-M-DD", "2009-5-28"); 57 | 58 | testDate(SUCCESS, "2009-10-28", "YY-M-DD", "09-10-28"); 59 | testDate(SUCCESS, "2009-10-03", "YY-M-DD", "09-10-03"); 60 | testDate(SUCCESS, "2099-05-28", "YY-M-DD", "99-5-28"); 61 | 62 | testDate(SUCCESS, "2099-05-28", "YYYYMMDD", "20990528"); 63 | testDate(SUCCESS, "2099-11-28", "WWW MMM DD, YYYY", Locale.CANADA, "Sat Nov 28, 2099"); 64 | testDate(SUCCESS, "2099-11-28", "WWW-DD|th|", Locale.CANADA, "Sat-28th"); 65 | 66 | testDate(SUCCESS, "2009-12-31", "MM-DD-YYYY", "12-31-2009"); 67 | 68 | testDate(SUCCESS, "2009-12-31", "***YYYY-MM-DD", "***2009-12-31"); 69 | testDate(SUCCESS, "2009-12-31", "***YYYY-MM-DD*", "***2009-12-31*"); 70 | testDate(SUCCESS, "2009-12-31", "* YYYY-MM-DD *", "* 2009-12-31 *"); 71 | 72 | testDate(SUCCESS, "2009-12-31", "WWWW, MMM D, YYYY", Locale.CANADA, "Thursday, Dec 31, 2009"); 73 | testDate(SUCCESS, "2009-12-31", "WWW, MMM D, YYYY", Locale.CANADA, "Thu, Dec 31, 2009"); 74 | 75 | testDate(SUCCESS, "01:59:59", "hh:mm:ss", "01:59:59"); 76 | testDate(SUCCESS, "01:59:59", "h:mm:ss", "1:59:59"); 77 | testDate(SUCCESS, "01:59:59", "hh:m:ss", "01:59:59"); 78 | testDate(SUCCESS, "01:01:59", "hh:m:ss", "01:1:59"); 79 | testDate(SUCCESS, "01:59:59", "hh:mm:s", "01:59:59"); 80 | testDate(SUCCESS, "01:59:01", "hh:mm:s", "01:59:1"); 81 | testDate(SUCCESS, "01:59:01.123456789", "hh:mm:ss", "01:59:01"); 82 | testDate(SUCCESS, "01:59:01.123456789", "hh:mm:ss.f", "01:59:01.1"); 83 | testDate(SUCCESS, "01:59:01.123456789", "hh:mm:ss.ff", "01:59:01.12"); 84 | testDate(SUCCESS, "01:59:01.123456789", "hh:mm:ss.fff", "01:59:01.123"); 85 | testDate(SUCCESS, "01:59:01.123456789", "hh:mm:ss.ffff", "01:59:01.1234"); 86 | testDate(SUCCESS, "01:59:01.123456789", "hh:mm:ss.fffff", "01:59:01.12345"); 87 | testDate(SUCCESS, "01:59:01.123456789", "hh:mm:ss.ffffff", "01:59:01.123456"); 88 | testDate(SUCCESS, "01:59:01.123456789", "hh:mm:ss.fffffff", "01:59:01.1234567"); 89 | testDate(SUCCESS, "01:59:01.123456789", "hh:mm:ss.ffffffff", "01:59:01.12345678"); 90 | testDate(SUCCESS, "01:59:01.123456789", "hh:mm:ss.fffffffff", "01:59:01.123456789"); 91 | 92 | testDate(SUCCESS, "01:59:01", "hh", "01"); 93 | testDate(SUCCESS, "01:59:01", "mm", "59"); 94 | testDate(SUCCESS, "01:59:01", "ss", "01"); 95 | testDate(SUCCESS, "01:59:01", "hh ", "01 "); 96 | testDate(SUCCESS, "01:59:01", "hh:mm", "01:59"); 97 | testDate(SUCCESS, "01:59:01", "h:mm", "1:59"); 98 | testDate(SUCCESS, "01:59:01", "mm:ss", "59:01"); 99 | testDate(SUCCESS, "01:59:01", "mm:s", "59:1"); 100 | 101 | testDate(SUCCESS, "2009-10-28 01:59:01", "YYYY-MM-DD hh:mm:ss", "2009-10-28 01:59:01"); 102 | testDate(SUCCESS, "2009-10-28 01:59:01", "YYYYMMDDThh:mm:ss", "20091028T01:59:01"); 103 | testDate(SUCCESS, "2009-10-28 01:59:01", "YYYY-MMM-DD hh:mm:ss", Locale.CANADA, "2009-Oct-28 01:59:01"); 104 | testDate(SUCCESS, "2009-10-28 01:59:01", "YYYY-MMM-DD", Locale.CANADA, "2009-Oct-28"); 105 | testDate(SUCCESS, "2009-10-28 01:59:01", ":hh:mm:ss:", ":01:59:01:"); 106 | testDate(SUCCESS, "2009-04-28 13:59:01", "DD MMM, YYYY hh:mm:ss", Locale.CANADA_FRENCH, "28 avr, 2009 13:59:01"); 107 | 108 | 109 | testDate(SUCCESS, "01:59:01.01", "hh:mm:ss.ff", "01:59:01.01"); 110 | testDate(SUCCESS, "01:59:01.01", "hh:mm:ss.fff", "01:59:01.010"); 111 | testDate(SUCCESS, "01:59:01.01", "hh:mm:ss.ffff", "01:59:01.0100"); 112 | testDate(SUCCESS, "01:59:01.01", "hh:mm:ss.fffff", "01:59:01.01000"); 113 | testDate(SUCCESS, "01:59:01.01", "hh:mm:ss.ffffff", "01:59:01.010000"); 114 | testDate(SUCCESS, "01:59:01.01", "hh:mm:ss.fffffff", "01:59:01.0100000"); 115 | testDate(SUCCESS, "01:59:01.01", "hh:mm:ss.ffffffff", "01:59:01.01000000"); 116 | testDate(SUCCESS, "01:59:01.01", "hh:mm:ss.fffffffff", "01:59:01.010000000"); 117 | 118 | testDate(SUCCESS, "01:59:01.000000001", "hh:mm:ss", "01:59:01"); 119 | testDate(SUCCESS, "01:59:01.000000001", "hh:mm:ss.f", "01:59:01.0"); 120 | testDate(SUCCESS, "01:59:01.000000001", "hh:mm:ss.ff", "01:59:01.00"); 121 | testDate(SUCCESS, "01:59:01.000000001", "hh:mm:ss.fff", "01:59:01.000"); 122 | testDate(SUCCESS, "01:59:01.000000001", "hh:mm:ss.ffff", "01:59:01.0000"); 123 | testDate(SUCCESS, "01:59:01.000000001", "hh:mm:ss.fffff", "01:59:01.00000"); 124 | testDate(SUCCESS, "01:59:01.000000001", "hh:mm:ss.ffffff", "01:59:01.000000"); 125 | testDate(SUCCESS, "01:59:01.000000001", "hh:mm:ss.fffffff", "01:59:01.0000000"); 126 | testDate(SUCCESS, "01:59:01.000000001", "hh:mm:ss.ffffffff", "01:59:01.00000000"); 127 | testDate(SUCCESS, "01:59:01.000000001", "hh:mm:ss.fffffffff", "01:59:01.000000001"); 128 | 129 | testDate(SUCCESS, "01:59:01.000000000", "hh:mm:ss.fffffffff", "01:59:01.000000000"); 130 | 131 | testDate(SUCCESS, "2009-10-28 01:59:01", "YYYY-MM-DD h12:mm:ss", "2009-10-28 1:59:01"); 132 | testDate(SUCCESS, "2009-10-28 13:59:01", "YYYY-MM-DD h12:mm:ss", "2009-10-28 1:59:01"); 133 | 134 | testDate(SUCCESS, "2009-10-28 01:59:01", "YYYY-MM-DD hh12:mm:ss", "2009-10-28 01:59:01"); 135 | testDate(SUCCESS, "2009-10-28 12:59:01", "YYYY-MM-DD hh12:mm:ss", "2009-10-28 12:59:01"); 136 | testDate(SUCCESS, "2009-10-28 13:59:01", "YYYY-MM-DD hh12:mm:ss", "2009-10-28 01:59:01"); 137 | testDate(SUCCESS, "2009-10-28 23:59:01", "YYYY-MM-DD hh12:mm:ss", "2009-10-28 11:59:01"); 138 | 139 | testDate(SUCCESS, "2009-10-28 01:59:01", "YYYY-MM-DD h12:mm:ss a", Locale.CANADA, "2009-10-28 1:59:01 AM"); 140 | testDate(SUCCESS, "2009-10-28 13:59:01", "YYYY-MM-DD h12:mm:ss a", Locale.CANADA, "2009-10-28 1:59:01 PM"); 141 | 142 | //WRONG : 143 | //this fails - tokens cannot appear next to each other: 144 | //testDate(SUCCESS, "2009-10-28 13:59:01", "YYYY-MM-DD h12:mm:ssa", Locale.CANADA, "2009-10-28 1:59:01PM"); 145 | //the workaround for the above is to use the escape character, with nothing in between: 146 | testDate(SUCCESS, "2009-10-28 13:59:01", "YYYY-MM-DD h12:mm:ss||a", Locale.CANADA, "2009-10-28 1:59:01PM"); 147 | } 148 | 149 | public void testEscapeChar(){ 150 | testDate(SUCCESS, "2009-10-28 01:59:01", "|Date:|YYYY-MM-DD |Time:|hh12:mm:ss", "Date:2009-10-28 Time:01:59:01"); 151 | testDate(SUCCESS, "15:59:59", "h12| o'clock| a", Locale.CANADA, "3 o'clock PM"); 152 | //inside escaped regions, the tokens are uninterpreted : 153 | testDate(SUCCESS, "2009-10-28 01:59:01", "|Date(YYYY-MM-DD):|YYYY-MM-DD |Timehh12:mm:ss:|hh12:mm:ss", "Date(YYYY-MM-DD):2009-10-28 Timehh12:mm:ss:01:59:01"); 154 | } 155 | 156 | public void testCustomFormats() { 157 | List months = Arrays.asList("J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"); 158 | List weekdays = Arrays.asList("sunday", "monday", "tuesday", "humpday", "thursday", "friday", "saturday"); 159 | List amPm = Arrays.asList("am", "pm"); 160 | testDate(SUCCESS, "2009-10-28 01:59:01", "YYYY-MM-DD hh:mm:ss a", months, weekdays, amPm, "2009-10-28 01:59:01 am"); 161 | testDate(SUCCESS, "2009-10-28 16:59:01", "YYYY-MM-DD h12:mm:ss a", months, weekdays, amPm, "2009-10-28 4:59:01 pm"); 162 | 163 | testDate(SUCCESS, "2009-10-28 01:59:01", "YYYY-MMMM-DD hh:mm:ss a", months, weekdays, amPm, "2009-O-28 01:59:01 am"); 164 | testDate(SUCCESS, "2009-10-28 01:59:01", "YYYY-MM-DD WWWW hh:mm:ss a", months, weekdays, amPm, "2009-10-28 humpday 01:59:01 am"); 165 | } 166 | 167 | // PRIVATE 168 | 169 | private static final boolean SUCCESS = true; 170 | 171 | private void testDate(boolean aSuccess, String aDate , String aFormat, String aExpectedResult){ 172 | DateTimeParser parser = new DateTimeParser(); 173 | DateTime dateTime = parser.parse(aDate); 174 | DateTimeFormatter formatter = new DateTimeFormatter(aFormat); 175 | String result = formatter.format(dateTime); 176 | if(aSuccess){ 177 | if(! result.equals(aExpectedResult)){ 178 | throw new AssertionError("Expected:" + aExpectedResult + ", but result was:" + result); 179 | } 180 | } 181 | else { 182 | assertFalse(result.equals(aExpectedResult)); 183 | } 184 | } 185 | 186 | private void testDate(boolean aSuccess, String aDate , String aFormat, Locale aLocale, String aExpectedResult){ 187 | DateTimeParser parser = new DateTimeParser(); 188 | DateTime dateTime = parser.parse(aDate); 189 | DateTimeFormatter formatter = new DateTimeFormatter(aFormat, aLocale); 190 | String result = formatter.format(dateTime); 191 | if(aSuccess){ 192 | if(! result.equals(aExpectedResult)){ 193 | throw new AssertionError("Expected:" + aExpectedResult + ", but result was:" + result); 194 | } 195 | } 196 | else { 197 | assertFalse(result.equals(aExpectedResult)); 198 | } 199 | } 200 | 201 | private void testDate(boolean aSuccess, String aDate , String aFormat, List aMonths, List aWeekdays, List aAmPm, String aExpectedResult){ 202 | DateTimeParser parser = new DateTimeParser(); 203 | DateTime dateTime = parser.parse(aDate); 204 | DateTimeFormatter formatter = new DateTimeFormatter(aFormat, aMonths, aWeekdays, aAmPm); 205 | String result = formatter.format(dateTime); 206 | if(aSuccess){ 207 | if(! result.equals(aExpectedResult)){ 208 | throw new AssertionError("Expected:" + aExpectedResult + ", but result was:" + result); 209 | } 210 | } 211 | else { 212 | assertFalse(result.equals(aExpectedResult)); 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /docs/javadoc/serialized-form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Serialized Form (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 46 | 49 | 50 | 51 | 52 | 55 | 71 | 72 |
47 | Version 1.5.1 48 |
73 | 74 | 75 | 76 |
77 |
78 |

79 | Serialized Form

80 |
81 |
82 | 83 | 84 | 85 | 87 | 88 |
86 | Package hirondelle.date4j
89 | 90 |

91 | 92 | 93 | 94 | 96 | 97 |
95 | Class hirondelle.date4j.DateTime extends Object implements Serializable
98 | 99 |

100 | serialVersionUID: -1300068157085493891L 101 | 102 |

103 | 104 | 105 | 106 | 108 | 109 |
107 | Serialization Methods
110 | 111 |

112 |

113 | readObject

114 |
115 | private void readObject(ObjectInputStream aInputStream)
116 |                  throws ClassNotFoundException,
117 |                         IOException
118 |
119 |
Always treat de-serialization as a full-blown constructor, by 120 | validating the final state of the de-serialized object. 121 |

122 |

123 | 124 |
Throws: 125 |
ClassNotFoundException 126 |
IOException
127 |
128 |
129 |
130 |

131 | writeObject

132 |
133 | private void writeObject(ObjectOutputStream aOutputStream)
134 |                   throws IOException
135 |
136 |
This is the default implementation of writeObject. 137 | Customise if necessary. 138 |

139 |

140 | 141 |
Throws: 142 |
IOException
143 |
144 |
145 | 146 | 147 | 148 | 150 | 151 |
149 | Serialized Fields
152 | 153 |

154 | fDateTime

155 |
156 | String fDateTime
157 |
158 |
The text form of a date. @serial 159 |

160 |

161 |
162 |
163 |
164 |

165 | fYear

166 |
167 | Integer fYear
168 |
169 |
 
170 |
171 |
172 |
173 |

174 | fMonth

175 |
176 | Integer fMonth
177 |
178 |
 
179 |
180 |
181 |
182 |

183 | fDay

184 |
185 | Integer fDay
186 |
187 |
 
188 |
189 |
190 |
191 |

192 | fHour

193 |
194 | Integer fHour
195 |
196 |
 
197 |
198 |
199 |
200 |

201 | fMinute

202 |
203 | Integer fMinute
204 |
205 |
 
206 |
207 |
208 |
209 |

210 | fSecond

211 |
212 | Integer fSecond
213 |
214 |
 
215 |
216 |
217 |
218 |

219 | fNanosecond

220 |
221 | Integer fNanosecond
222 |
223 |
 
224 |
225 |
226 |
227 |

228 | fIsAlreadyParsed

229 |
230 | boolean fIsAlreadyParsed
231 |
232 |
Indicates if this DateTime has been parsed into its 7 constituents. @serial 233 |

234 |

235 |
236 |
237 |
238 |

239 | fHashCode

240 |
241 | int fHashCode
242 |
243 |
 
244 |
245 |
246 | 247 |

248 |


249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 270 | 273 | 274 | 275 | 276 | 279 | 295 | 296 |
271 | Version 1.5.1 272 |
297 | 298 | 299 | 300 |
301 | Copyright Hirondelle Systems. Published November 19, 2013 302 | 303 | 304 | -------------------------------------------------------------------------------- /classes/hirondelle/date4j/ToStringUtil.java: -------------------------------------------------------------------------------- 1 | package hirondelle.date4j; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Modifier; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.StringTokenizer; 9 | import java.util.logging.Logger; 10 | import java.util.regex.Matcher; 11 | import java.util.regex.Pattern; 12 | 13 | /** 14 | Implements the toString method for some common cases. 15 | 16 |

This class is intended only for cases where toString is used in 17 | an informal manner (usually for logging and stack traces). It is especially 18 | suited for public classes which model domain objects. 19 | 20 | Here is an example of a return value of the {@link #getText} method : 21 |

 22 | hirondelle.web4j.model.MyUser {
 23 | LoginName: Bob
 24 | LoginPassword: ****
 25 | EmailAddress: bob@blah.com
 26 | StarRating: 1
 27 | FavoriteTheory: Quantum Chromodynamics
 28 | SendCard: true
 29 | Age: 42
 30 | DesiredSalary: 42000
 31 | BirthDate: Sat Feb 26 13:45:43 EST 2005
 32 | }
 33 |  
34 | (Previous versions of this classes used indentation within the braces. That has 35 | been removed, since it displays poorly when nesting occurs.) 36 | 37 |

Here are two more examples, using classes taken from the JDK : 38 |

 39 | java.util.StringTokenizer {
 40 | nextElement: This
 41 | hasMoreElements: true
 42 | countTokens: 3
 43 | nextToken: is
 44 | hasMoreTokens: true
 45 | }
 46 | 
 47 | java.util.ArrayList {
 48 | size: 3
 49 | toArray: [blah, blah, blah]
 50 | isEmpty: false
 51 | }
 52 |  
53 | 54 | There are two use cases for this class. The typical use case is : 55 |
 56 |   public String toString() {
 57 |     return ToStringUtil.getText(this);
 58 |   }
 59 |  
60 | 61 | However, there is a case where this typical style can 62 | fail catastrophically : when two objects reference each other, and each 63 | has toString implemented as above, then the program will loop 64 | indefinitely! 65 | 66 |

As a remedy for this problem, the following variation is provided : 67 |

 68 |   public String toString() {
 69 |     return ToStringUtil.getTextAvoidCyclicRefs(this, Product.class, "getId");
 70 |   }
 71 |  
72 | Here, the usual behavior is overridden for any method 73 | which returns a Product : instead of calling Product.toString, 74 | the return value of Product.getId() is used to textually represent 75 | the object. 76 | */ 77 | final class ToStringUtil { 78 | 79 | /** 80 | Return an informal textual description of an object. 81 |

It is highly recommened that the caller not rely on details 82 | of the returned String. See class description for examples of return 83 | values. 84 | 85 |

WARNING: If two classes have cyclic references 86 | (that is, each has a reference to the other), then infinite looping will result 87 | if both call this method! To avoid this problem, use getText 88 | for one of the classes, and {@link #getTextAvoidCyclicRefs} for the other class. 89 | 90 |

The only items which contribute to the result are the class name, and all 91 | no-argument public methods which return a value. As well, methods 92 | defined by the Object class, and factory methods which return an 93 | Object of the native class ("getInstance" methods) do not contribute. 94 | 95 |

Items are converted to a String simply by calling their 96 | toString method, with these exceptions : 97 |

    98 |
  • {@link Util#getArrayAsString(Object)} is used for arrays 99 |
  • a method whose name contain the text "password" (not case-sensitive) have 100 | their return values hard-coded to "****". 101 |
102 | 103 |

If the method name follows the pattern getXXX, then the word 'get' 104 | is removed from the presented result. 105 | 106 | @param aObject the object for which a toString result is required. 107 | */ 108 | static String getText(Object aObject) { 109 | return getTextAvoidCyclicRefs(aObject, null, null); 110 | } 111 | 112 | /** 113 | As in {@link #getText}, but, for return values which are instances of 114 | aSpecialClass, then call aMethodName instead of toString. 115 | 116 |

If aSpecialClass and aMethodName are null, then the 117 | behavior is exactly the same as calling {@link #getText}. 118 | */ 119 | static String getTextAvoidCyclicRefs(Object aObject, Class aSpecialClass, String aMethodName) { 120 | StringBuilder result = new StringBuilder(); 121 | addStartLine(aObject, result); 122 | 123 | Method[] methods = aObject.getClass().getDeclaredMethods(); 124 | for(Method method: methods){ 125 | if ( isContributingMethod(method, aObject.getClass()) ){ 126 | addLineForGetXXXMethod(aObject, method, result, aSpecialClass, aMethodName); 127 | } 128 | } 129 | 130 | addEndLine(result); 131 | return result.toString(); 132 | } 133 | 134 | // PRIVATE // 135 | 136 | /* 137 | Names of methods in the Object class which are ignored. 138 | */ 139 | private static final String fGET_CLASS = "getClass"; 140 | private static final String fCLONE = "clone"; 141 | private static final String fHASH_CODE = "hashCode"; 142 | private static final String fTO_STRING = "toString"; 143 | 144 | private static final String fGET = "get"; 145 | private static final Object[] fNO_ARGS = new Object[0]; 146 | private static final Class[] fNO_PARAMS = new Class[0]; 147 | /* 148 | Previous versions of this class indented the data within a block. 149 | That style breaks when one object references another. The indentation 150 | has been removed, but this variable has been retained, since others might 151 | prefer the indentation anyway. 152 | */ 153 | private static final String fINDENT = ""; 154 | private static final String fAVOID_CIRCULAR_REFERENCES = "[circular reference]"; 155 | private static final Logger fLogger = Util.getLogger(ToStringUtil.class); 156 | private static final String NEW_LINE = System.getProperty("line.separator"); 157 | 158 | private static Pattern PASSWORD_PATTERN = Pattern.compile("password", Pattern.CASE_INSENSITIVE); 159 | private static String HIDDEN_PASSWORD_VALUE = "****"; 160 | 161 | //prevent construction by the caller 162 | private ToStringUtil() { 163 | //empty 164 | } 165 | 166 | private static void addStartLine(Object aObject, StringBuilder aResult){ 167 | aResult.append( aObject.getClass().getName() ); 168 | aResult.append(" {"); 169 | aResult.append(NEW_LINE); 170 | } 171 | 172 | private static void addEndLine(StringBuilder aResult){ 173 | aResult.append("}"); 174 | aResult.append(NEW_LINE); 175 | } 176 | 177 | /** 178 | Return true only if aMethod is public, takes no args, 179 | returns a value whose class is not the native class, is not a method of 180 | Object. 181 | */ 182 | private static boolean isContributingMethod(Method aMethod, Class aNativeClass){ 183 | boolean isPublic = Modifier.isPublic( aMethod.getModifiers() ); 184 | boolean hasNoArguments = aMethod.getParameterTypes().length == 0; 185 | boolean hasReturnValue = aMethod.getReturnType() != Void.TYPE; 186 | boolean returnsNativeObject = aMethod.getReturnType() == aNativeClass; 187 | boolean isMethodOfObjectClass = 188 | aMethod.getName().equals(fCLONE) || 189 | aMethod.getName().equals(fGET_CLASS) || 190 | aMethod.getName().equals(fHASH_CODE) || 191 | aMethod.getName().equals(fTO_STRING) 192 | ; 193 | return 194 | isPublic && 195 | hasNoArguments && 196 | hasReturnValue && 197 | ! isMethodOfObjectClass && 198 | ! returnsNativeObject; 199 | } 200 | 201 | private static void addLineForGetXXXMethod( 202 | Object aObject, 203 | Method aMethod, 204 | StringBuilder aResult, 205 | Class aCircularRefClass, 206 | String aCircularRefMethodName 207 | ){ 208 | aResult.append(fINDENT); 209 | aResult.append( getMethodNameMinusGet(aMethod) ); 210 | aResult.append(": "); 211 | Object returnValue = getMethodReturnValue(aObject, aMethod); 212 | if ( returnValue != null && returnValue.getClass().isArray() ) { 213 | aResult.append( Util.getArrayAsString(returnValue) ); 214 | } 215 | else { 216 | if (aCircularRefClass == null) { 217 | aResult.append( returnValue ); 218 | } 219 | else { 220 | if (aCircularRefClass == returnValue.getClass()) { 221 | Method method = getMethodFromName(aCircularRefClass, aCircularRefMethodName); 222 | if ( isContributingMethod(method, aCircularRefClass)){ 223 | returnValue = getMethodReturnValue(returnValue, method); 224 | aResult.append( returnValue ); 225 | } 226 | else { 227 | aResult.append(fAVOID_CIRCULAR_REFERENCES); 228 | } 229 | } 230 | } 231 | } 232 | aResult.append( NEW_LINE ); 233 | } 234 | 235 | private static String getMethodNameMinusGet(Method aMethod){ 236 | String result = aMethod.getName(); 237 | if (result.startsWith(fGET) ) { 238 | result = result.substring(fGET.length()); 239 | } 240 | return result; 241 | } 242 | 243 | /** Return value is possibly-null. */ 244 | private static Object getMethodReturnValue(Object aObject, Method aMethod){ 245 | Object result = null; 246 | try { 247 | result = aMethod.invoke(aObject, fNO_ARGS); 248 | } 249 | catch (IllegalAccessException ex){ 250 | vomit(aObject, aMethod); 251 | } 252 | catch (InvocationTargetException ex){ 253 | vomit(aObject, aMethod); 254 | } 255 | result = dontShowPasswords(result, aMethod); 256 | return result; 257 | } 258 | 259 | private static Method getMethodFromName(Class aSpecialClass, String aMethodName){ 260 | Method result = null; 261 | try { 262 | result = aSpecialClass.getMethod(aMethodName, fNO_PARAMS); 263 | } 264 | catch ( NoSuchMethodException ex){ 265 | vomit(aSpecialClass, aMethodName); 266 | } 267 | return result; 268 | } 269 | 270 | 271 | private static void vomit(Object aObject, Method aMethod){ 272 | fLogger.severe( 273 | "Cannot get return value using reflection. Class: " + 274 | aObject.getClass().getName() + 275 | " Method: " + 276 | aMethod.getName() 277 | ); 278 | } 279 | 280 | private static void vomit(Class aSpecialClass, String aMethodName){ 281 | fLogger.severe( 282 | "Reflection fails to get no-arg method named: " + 283 | Util.quote(aMethodName) + 284 | " for class: " + 285 | aSpecialClass.getName() 286 | ); 287 | } 288 | 289 | private static Object dontShowPasswords(Object aReturnValue, Method aMethod){ 290 | Object result = aReturnValue; 291 | Matcher matcher = PASSWORD_PATTERN.matcher(aMethod.getName()); 292 | if ( matcher.find()) { 293 | result = HIDDEN_PASSWORD_VALUE; 294 | } 295 | return result; 296 | } 297 | 298 | /* 299 | Two informal classes with cyclic references, used for testing. 300 | */ 301 | private static final class Ping { 302 | public void setPong(Pong aPong){fPong = aPong; } 303 | public Pong getPong(){ return fPong; } 304 | public Integer getId() { return new Integer(123); } 305 | public String getUserPassword(){ return "blah"; } 306 | public String toString() { 307 | return getText(this); 308 | } 309 | private Pong fPong; 310 | } 311 | private static final class Pong { 312 | public void setPing(Ping aPing){ fPing = aPing; } 313 | public Ping getPing() { return fPing; } 314 | public String toString() { 315 | return getTextAvoidCyclicRefs(this, Ping.class, "getId"); 316 | //to see the infinite looping, use this instead : 317 | //return getText(this); 318 | } 319 | private Ping fPing; 320 | } 321 | 322 | /** 323 | Informal test harness. 324 | */ 325 | public static void main (String... args) { 326 | List list = new ArrayList(); 327 | list.add("blah"); 328 | list.add("blah"); 329 | list.add("blah"); 330 | System.out.println( ToStringUtil.getText(list) ); 331 | 332 | StringTokenizer parser = new StringTokenizer("This is the end."); 333 | System.out.println( ToStringUtil.getText(parser) ); 334 | 335 | Ping ping = new Ping(); 336 | Pong pong = new Pong(); 337 | ping.setPong(pong); 338 | pong.setPing(ping); 339 | System.out.println( ping ); 340 | System.out.println( pong ); 341 | } 342 | } 343 | -------------------------------------------------------------------------------- /docs/javadoc/src-html/hirondelle/date4j/Examples.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Examples.java 5 | 6 | 7 | 8 | 9 |

 10 | package hirondelle.date4j;
 11 | 
 12 | import java.util.Locale;
 13 | import java.util.TimeZone;
 14 | 
 15 | /** Examples of how to use date4j. */
 16 | public final class Examples {
 17 | 
 18 |   /** 
 19 |    Run the examples, and output to the console. 
 20 |    
 21 |   <P>Example output when you run this class: 
 22 |   <PRE>
 23 |    Current date-time in default time zone : 2011-10-24 08:05:59
 24 |    Current date-time in Cairo : 2011-10-24 13:06:00 (Monday)
 25 |    Age of someone born May 16, 1995 is : 16
 26 |    The 3rd Friday of this month is : 2011-10-21
 27 |    Number of days till Christmas : 62
 28 |    90 days from today is : 2012-01-22
 29 |    3 months and 5 days from today is : 2012-01-29
 30 |    Numbers of hours difference between Paris and Perth : 6
 31 |    The number of weeks since Sep 6, 2010 : 59
 32 |    This many seconds till midnight : 57240
 33 |    Output using an ISO format: 2011-10-24T08:06:00
 34 |    The first day of this week is : 2011-10-23
 35 |    The number of years the JDK date-time API has been suctorial : 15
 36 |   </PRE>  
 37 |   */
 38 |   public static void main(String... aArgs){
 39 |     Examples examples = new Examples();
 40 |     examples.currentDateTime();
 41 |     examples.currentDateTimeInCairo();
 42 |     examples.ageIfBornOnCertainDate();
 43 |     examples.optionsExpiry();
 44 |     examples.daysTillChristmas();
 45 |     examples.whenIs90DaysFromToday();
 46 |     examples.whenIs3Months5DaysFromToday();
 47 |     examples.hoursDifferenceBetweenParisAndPerth();
 48 |     examples.weeksSinceStart();
 49 |     examples.timeTillMidnight();
 50 |     examples.imitateISOFormat();
 51 |     examples.firstDayOfThisWeek();
 52 |     examples.jdkDatesSuctorial();
 53 |   }
 54 |   
 55 |   // PRIVATE
 56 |   
 57 |   private static void log(Object aMsg){
 58 |     System.out.println(String.valueOf(aMsg));
 59 |   }
 60 |   
 61 |   /** What is the current date-time in the JRE's default time zone? */
 62 |   private void currentDateTime(){
 63 |     DateTime now = DateTime.now(TimeZone.getDefault());
 64 |     String result = now.format("YYYY-MM-DD hh:mm:ss");
 65 |     log("Current date-time in default time zone : " + result);
 66 |   }
 67 |   
 68 |   /** What is the current date-time in Cairo (include weekday)? */
 69 |   private void currentDateTimeInCairo(){
 70 |     DateTime now = DateTime.now(TimeZone.getTimeZone("Africa/Cairo"));
 71 |     String result = now.format("YYYY-MM-DD hh:mm:ss (WWWW)", Locale.getDefault());
 72 |     log("Current date-time in Cairo : " + result);
 73 |   }
 74 |   
 75 |   /** What's the age of someone born May 16, 1995? */
 76 |   private void ageIfBornOnCertainDate(){
 77 |     DateTime today = DateTime.today(TimeZone.getDefault());
 78 |     DateTime birthdate = DateTime.forDateOnly(1995, 5, 16);
 79 |     int age = today.getYear() - birthdate.getYear();
 80 |     if(today.getDayOfYear() < birthdate.getDayOfYear()){
 81 |       age = age - 1; 
 82 |     }
 83 |     log("Age of someone born May 16, 1995 is : " + age);
 84 |   }
 85 |   
 86 |   /** Stock options expire on the 3rd Friday of this month. What day of the month is that? */
 87 |   private void optionsExpiry(){
 88 |     DateTime today = DateTime.today(TimeZone.getDefault());
 89 |     DateTime firstOfMonth = today.getStartOfMonth();
 90 |     int result = 0;
 91 |     if (firstOfMonth.getWeekDay() == 7){
 92 |       result = 21;
 93 |     }
 94 |     else {
 95 |        result = 21 - firstOfMonth.getWeekDay();
 96 |     }
 97 |     DateTime thirdFriday = DateTime.forDateOnly(firstOfMonth.getYear(), firstOfMonth.getMonth(), result);
 98 |     log("The 3rd Friday of this month is : " + thirdFriday.format("YYYY-MM-DD"));
 99 |   }
100 |   
101 |   /** How many days till the next December 25? */
102 |   private void daysTillChristmas(){
103 |     DateTime today = DateTime.today(TimeZone.getDefault());
104 |     DateTime christmas = DateTime.forDateOnly(today.getYear(), 12, 25);
105 |     int result = 0;
106 |     if(today.isSameDayAs(christmas)){
107 |       // do nothing
108 |     }
109 |     else if (today.lt(christmas)){
110 |       result = today.numDaysFrom(christmas);
111 |     }
112 |     else if (today.gt(christmas)){
113 |       DateTime christmasNextYear = DateTime.forDateOnly(today.getYear() + 1, 12, 25);
114 |       result = today.numDaysFrom(christmasNextYear);
115 |     }
116 |     log("Number of days till Christmas : " + result);
117 |   }
118 |   
119 |   /** What day is 90 days from today? */
120 |   private void whenIs90DaysFromToday(){
121 |     DateTime today = DateTime.today(TimeZone.getDefault());
122 |     log("90 days from today is : " + today.plusDays(90).format("YYYY-MM-DD"));
123 |   }
124 | 
125 |   /** What day is 3 months and 5 days from today? */
126 |   private void whenIs3Months5DaysFromToday(){
127 |     DateTime today = DateTime.today(TimeZone.getDefault());
128 |     DateTime result = today.plus(0,3,5,0,0,0,0,DateTime.DayOverflow.FirstDay);
129 |     log("3 months and 5 days from today is : " + result.format("YYYY-MM-DD"));
130 |   }
131 |   
132 |   /** Current number of hours difference between Paris, France and Perth, Australia. */
133 |   private void hoursDifferenceBetweenParisAndPerth(){
134 |     //this assumes the time diff is a whole number of hours; other styles are possible
135 |     DateTime paris = DateTime.now(TimeZone.getTimeZone("Europe/Paris"));
136 |     DateTime perth = DateTime.now(TimeZone.getTimeZone("Australia/Perth"));
137 |     int result = perth.getHour() - paris.getHour();
138 |     if( result < 0 ) {
139 |       result = result + 24;
140 |     }
141 |     log("Numbers of hours difference between Paris and Perth : " + result);
142 |   }
143 |   
144 |   /** How many weeks is it since Sep 6, 2010? */
145 |   private void weeksSinceStart(){
146 |     DateTime today = DateTime.today(TimeZone.getDefault());
147 |     DateTime startOfProject = DateTime.forDateOnly(2010, 9, 6);
148 |     int result = today.getWeekIndex() - startOfProject.getWeekIndex();
149 |     log("The number of weeks since Sep 6, 2010 : " + result);
150 |   }
151 |   
152 |   /** How much time till midnight? */
153 |   private void timeTillMidnight(){
154 |     DateTime now = DateTime.now(TimeZone.getDefault());
155 |     DateTime midnight = now.plusDays(1).getStartOfDay();
156 |     long result = now.numSecondsFrom(midnight);
157 |     log("This many seconds till midnight : " + result);
158 |   }
159 |   
160 |   /** Format using ISO style. */
161 |   private void imitateISOFormat(){
162 |     DateTime now = DateTime.now(TimeZone.getDefault());
163 |     log("Output using an ISO format: " + now.format("YYYY-MM-DDThh:mm:ss"));
164 |   }
165 | 
166 |   private void firstDayOfThisWeek(){
167 |     DateTime today = DateTime.today(TimeZone.getDefault()); 
168 |     DateTime firstDayThisWeek = today; //start value 
169 |     int todaysWeekday = today.getWeekDay();
170 |     int SUNDAY = 1;
171 |     if(todaysWeekday > SUNDAY){
172 |       int numDaysFromSunday = todaysWeekday - SUNDAY;
173 |       firstDayThisWeek = today.minusDays(numDaysFromSunday);
174 |     }
175 |     log("The first day of this week is : " + firstDayThisWeek);
176 |   }
177 |   
178 |   /** For how many years has the JDK date-time API been suctorial? */
179 |   private void jdkDatesSuctorial(){
180 |     DateTime today = DateTime.today(TimeZone.getDefault());
181 |     DateTime jdkFirstPublished = DateTime.forDateOnly(1996, 1, 23);
182 |     int result = today.getYear() - jdkFirstPublished.getYear();
183 |     log("The number of years the JDK date-time API has been suctorial : " + result);
184 |   }
185 |   
186 | } 
187 | 
188 | 189 | 190 | -------------------------------------------------------------------------------- /docs/javadoc/src-html/hirondelle/date4j/DateTimeParser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DateTimeParser.java 5 | 6 | 7 | 8 | 9 |
 10 | package hirondelle.date4j;
 11 | 
 12 | import java.util.regex.Matcher;
 13 | import java.util.regex.Pattern;
 14 | 
 15 | /**
 16 |  Convert a date-time from a string into a  {@link DateTime}.
 17 |  The primary use case for this class is converting date-times from a database <tt>ResultSet</tt>
 18 |  into a {@link DateTime}. It can also convert an ISO time, having a 'T' separating the date 
 19 |  from the time.
 20 | */
 21 | final class DateTimeParser  {
 22 | 
 23 |   /** 
 24 |    Thrown when the given string cannot be converted into a <tt>DateTime</tt>, since it doesn't 
 25 |    have a format allowed by this class. 
 26 |    An unchecked exception.
 27 |   */
 28 |   static final class UnknownDateTimeFormat extends RuntimeException {
 29 |     private static final long serialVersionUID = -7179421566055773208L;
 30 |     UnknownDateTimeFormat(String aMessage){   super(aMessage);   }
 31 |     UnknownDateTimeFormat(String aMessage, Throwable aEx){   super(aMessage, aEx);   }
 32 |   }
 33 |   
 34 |   DateTime parse(String aDateTime) {
 35 |     if(aDateTime == null){
 36 |       throw new NullPointerException("DateTime string is null");
 37 |     }
 38 |     String dateTime = aDateTime.trim();
 39 |     Parts parts = splitIntoDateAndTime(dateTime);
 40 |     if (parts.hasTwoParts()) {
 41 |       parseDate(parts.datePart);
 42 |       parseTime(parts.timePart);
 43 |     }
 44 |     else if (parts.hasDateOnly()){
 45 |       parseDate(parts.datePart);
 46 |     }
 47 |     else if (parts.hasTimeOnly()){
 48 |       parseTime(parts.timePart);
 49 |     }
 50 |     DateTime result = new DateTime(fYear, fMonth, fDay, fHour, fMinute, fSecond, fNanosecond);
 51 |     return result;
 52 |   }
 53 |   
 54 |   // PRIVATE
 55 |   
 56 |   /** 
 57 |    Gross pattern for dates. 
 58 |    Detailed validation is done by DateTime.
 59 |    The Group index VARIES for y-m-d according to which option is selected
 60 |    Year: Group 1, 4, 6
 61 |    Month: Group 2, 5
 62 |    Day: Group 3 
 63 |   */
 64 |   private static final Pattern DATE = Pattern.compile("(\\d{1,4})-(\\d\\d)-(\\d\\d)|(\\d{1,4})-(\\d\\d)|(\\d{1,4})");
 65 |   
 66 |   /** 
 67 |    Gross pattern for times. 
 68 |    Detailed validation is done by DateTime.   
 69 |    The Group index VARIES for h-m-s-f according to which option is selected
 70 |    Hour: Group 1, 5, 8, 10
 71 |    Minute: Group 2, 6, 9
 72 |    Second: Group 3, 7
 73 |    Microsecond:  Group 4
 74 |   */
 75 |   private static final String CL = "\\:"; //colon is a special character
 76 |   private static final String TT = "(\\d\\d)"; //colon is a special character
 77 |   private static final String NUM_DIGITS_FOR_FRACTIONAL_SECONDS = "9";
 78 |   private static final Integer NUM_DIGITS = Integer.valueOf(NUM_DIGITS_FOR_FRACTIONAL_SECONDS);
 79 |   private static final Pattern TIME = Pattern.compile("" +
 80 |       TT+CL+TT+CL+TT+ "\\." + "(\\d{1," + NUM_DIGITS_FOR_FRACTIONAL_SECONDS + "})" + "|" + 
 81 |       TT+CL+TT+CL+TT+ "|" + 
 82 |       TT+CL+TT+ "|" +
 83 |       TT
 84 |   );
 85 |   
 86 |   private static final String COLON = ":";
 87 |   private static final int THIRD_POSITION = 2;
 88 |   
 89 |   private Integer fYear;
 90 |   private Integer fMonth;
 91 |   private Integer fDay;
 92 |   private Integer fHour;
 93 |   private Integer fMinute;
 94 |   private Integer fSecond;
 95 |   private Integer fNanosecond;
 96 |   
 97 |   private class Parts {
 98 |     String datePart;
 99 |     String timePart;
100 |     boolean hasTwoParts(){
101 |       return datePart != null && timePart != null;
102 |     }
103 |     boolean hasDateOnly(){
104 |       return timePart == null;
105 |     }
106 |     boolean hasTimeOnly(){
107 |       return datePart == null;
108 |     }
109 |   }
110 |   
111 |   /** Date and time can be separated with a single space, or with a 'T' character (case-sensitive). */
112 |   private Parts splitIntoDateAndTime(String aDateTime){
113 |     Parts result = new Parts();
114 |     int dateTimeSeparator = getDateTimeSeparator(aDateTime);
115 |     boolean hasDateTimeSeparator = 0 < dateTimeSeparator  && dateTimeSeparator < aDateTime.length();
116 |     if (hasDateTimeSeparator){
117 |       result.datePart = aDateTime.substring(0, dateTimeSeparator);
118 |       result.timePart = aDateTime.substring(dateTimeSeparator+1);
119 |     }
120 |     else if(hasColonInThirdPlace(aDateTime)){
121 |       result.timePart = aDateTime;
122 |     }
123 |     else {
124 |       result.datePart = aDateTime;
125 |     }
126 |     return result;
127 |   }
128 |   
129 |   /** Return the index of a space character, or of a 'T' character. If not found, return -1.*/
130 |   int getDateTimeSeparator(String aDateTime){
131 |     String SPACE = " ";
132 |     int NOT_FOUND = -1;
133 |     int result = NOT_FOUND;
134 |     result = aDateTime.indexOf(SPACE);
135 |     if(result == NOT_FOUND){
136 |       result = aDateTime.indexOf("T");
137 |     }
138 |     return result;
139 |   }
140 |   
141 |   private boolean hasColonInThirdPlace(String aDateTime){
142 |     boolean result = false;
143 |     if(aDateTime.length() >= THIRD_POSITION){
144 |       result = COLON.equals(aDateTime.substring(THIRD_POSITION,THIRD_POSITION+1));
145 |     }
146 |     return result;
147 |   }
148 |   
149 |   private void parseDate(String aDate) {
150 |     Matcher matcher = DATE.matcher(aDate);
151 |     if (matcher.matches()){
152 |       String year = getGroup(matcher, 1, 4, 6);
153 |       if(year !=null ){
154 |         fYear = Integer.valueOf(year);
155 |       }
156 |       String month = getGroup(matcher, 2, 5);
157 |       if(month !=null ){
158 |         fMonth = Integer.valueOf(month);
159 |       }
160 |       String day = getGroup(matcher, 3);
161 |       if(day !=null ){
162 |         fDay = Integer.valueOf(day);
163 |       }
164 |     }
165 |     else {
166 |       throw new DateTimeParser.UnknownDateTimeFormat("Unexpected format for date:" + aDate);
167 |     }
168 |   }
169 | 
170 |   private String getGroup(Matcher aMatcher, int... aGroupIds){
171 |     String result = null;
172 |     for(int id: aGroupIds){
173 |       result = aMatcher.group(id);
174 |       if(result!=null) break;
175 |     }
176 |     return result;
177 |   }
178 | 
179 |   private void parseTime(String aTime) {
180 |     Matcher matcher = TIME.matcher(aTime);
181 |     if (matcher.matches()){
182 |       String hour = getGroup(matcher, 1, 5, 8, 10);
183 |       if(hour !=null ){
184 |         fHour = Integer.valueOf(hour);
185 |       }
186 |       String minute = getGroup(matcher, 2, 6, 9);
187 |       if(minute !=null ){
188 |         fMinute = Integer.valueOf(minute);
189 |       }
190 |       String second = getGroup(matcher, 3, 7);
191 |       if(second !=null ){
192 |         fSecond = Integer.valueOf(second);
193 |       }
194 |       String decimalSeconds = getGroup(matcher, 4);
195 |       if(decimalSeconds !=null ){
196 |         fNanosecond = Integer.valueOf(convertToNanoseconds(decimalSeconds));
197 |       }
198 |     }
199 |     else {
200 |       throw new DateTimeParser.UnknownDateTimeFormat("Unexpected format for time:" + aTime);
201 |     }
202 |   }
203 |   
204 |   /**
205 |    Convert any number of decimals (1..9) into the form it would have taken if nanos had been used, 
206 |    by adding any 0's to the right side.  
207 |   */
208 |   private String convertToNanoseconds(String aDecimalSeconds){
209 |     StringBuilder result = new StringBuilder(aDecimalSeconds);
210 |     while( result.length( ) < NUM_DIGITS ){
211 |       result.append("0");
212 |     }
213 |     return result.toString();
214 |   }
215 | }
216 |  
217 | 
218 | 219 | 220 | -------------------------------------------------------------------------------- /docs/javadoc/hirondelle/date4j/DateTime.Unit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | DateTime.Unit (DATE4J Javadoc) 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 47 | 50 | 51 | 52 | 53 | 56 | 72 | 73 | 74 | 76 | 78 | 79 |
48 | Version 1.5.1 49 |
80 | 81 | 82 | 83 |
84 | 85 |

86 | 87 | hirondelle.date4j 88 |
89 | Enum DateTime.Unit

90 |
 91 | Object
 92 |   extended by Enum<DateTime.Unit>
 93 |       extended by hirondelle.date4j.DateTime.Unit
 94 | 
95 |
96 |
All Implemented Interfaces:
Serializable, Comparable<DateTime.Unit>
97 |
98 |
99 |
Enclosing class:
DateTime
100 |
101 |
102 |
103 |
public static enum DateTime.Unit
extends Enum<DateTime.Unit>
104 | 105 | 106 |

107 | The seven parts of a DateTime object. The DAY represents the day of the month (1..31), not the weekday. 108 |

109 | 110 |

111 |


112 | 113 |

114 | 115 | 116 | 117 | 118 | 119 | 121 | 122 | 123 | 127 | 128 | 129 | 133 | 134 | 135 | 139 | 140 | 141 | 145 | 146 | 147 | 151 | 152 | 153 | 157 | 158 | 159 | 163 | 164 |
120 | Enum Constant Summary
DAY 124 | 125 |
126 |            
HOUR 130 | 131 |
132 |            
MINUTE 136 | 137 |
138 |            
MONTH 142 | 143 |
144 |            
NANOSECONDS 148 | 149 |
150 |            
SECOND 154 | 155 |
156 |            
YEAR 160 | 161 |
162 |            
165 |   166 | 167 | 168 | 169 | 170 | 171 | 173 | 174 | 175 | 177 | 181 | 182 | 183 | 185 | 190 | 191 |
172 | Method Summary
176 | static DateTime.UnitvalueOf(String name) 178 | 179 |
180 |           Returns the enum constant of this type with the specified name.
184 | static DateTime.Unit[]values() 186 | 187 |
188 |           Returns an array containing the constants of this enum type, in 189 | the order they're declared.
192 |   193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 |
Methods inherited from class Enum
clone, compareTo, equals, getDeclaringClass, hashCode, name, ordinal, toString, valueOf
201 |   202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 |
Methods inherited from class Object
finalize, getClass, notify, notifyAll, wait, wait, wait
210 |   211 |

212 | 213 | 214 | 215 | 216 | 217 | 218 | 220 | 221 |
219 | Enum Constant Detail
222 | 223 |

224 | YEAR

225 |
226 | public static final DateTime.Unit YEAR
227 |
228 |
229 |
230 |
231 |
232 | 233 |

234 | MONTH

235 |
236 | public static final DateTime.Unit MONTH
237 |
238 |
239 |
240 |
241 |
242 | 243 |

244 | DAY

245 |
246 | public static final DateTime.Unit DAY
247 |
248 |
249 |
250 |
251 |
252 | 253 |

254 | HOUR

255 |
256 | public static final DateTime.Unit HOUR
257 |
258 |
259 |
260 |
261 |
262 | 263 |

264 | MINUTE

265 |
266 | public static final DateTime.Unit MINUTE
267 |
268 |
269 |
270 |
271 |
272 | 273 |

274 | SECOND

275 |
276 | public static final DateTime.Unit SECOND
277 |
278 |
279 |
280 |
281 |
282 | 283 |

284 | NANOSECONDS

285 |
286 | public static final DateTime.Unit NANOSECONDS
287 |
288 |
289 |
290 |
291 | 292 | 293 | 294 | 295 | 296 | 297 | 299 | 300 |
298 | Method Detail
301 | 302 |

303 | values

304 |
305 | public static final DateTime.Unit[] values()
306 |
307 |
Returns an array containing the constants of this enum type, in 308 | the order they're declared. This method may be used to iterate 309 | over the constants as follows: 310 |
311 | for(DateTime.Unit c : DateTime.Unit.values())
312 |         System.out.println(c);
313 | 
314 |

315 |

316 | 317 |
Returns:
an array containing the constants of this enum type, in 318 | the order they're declared
319 |
320 |
321 |
322 | 323 |

324 | valueOf

325 |
326 | public static DateTime.Unit valueOf(String name)
327 |
328 |
Returns the enum constant of this type with the specified name. 329 | The string must match exactly an identifier used to declare an 330 | enum constant in this type. (Extraneous whitespace characters are 331 | not permitted.) 332 |

333 |

334 |
Parameters:
name - the name of the enum constant to be returned. 335 |
Returns:
the enum constant with the specified name 336 |
Throws: 337 |
IllegalArgumentException - if this enum type has no constant 338 | with the specified name
339 |
340 |
341 | 342 |
343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 364 | 367 | 368 | 369 | 370 | 373 | 389 | 390 | 391 | 393 | 395 | 396 |
365 | Version 1.5.1 366 |
397 | 398 | 399 | 400 |
401 | Copyright Hirondelle Systems. Published November 19, 2013 402 | 403 | 404 | --------------------------------------------------------------------------------