PK qS&)META-INF/MANIFEST.MFManifest-Version: 1.0 Name: com/markcrocker/thoughtworks/BadDateException.class Digest-Algorithms: SHA MD5 SHA-Digest: 7UgDTtz3NHNfFqcg2RbYGyM7I8E= MD5-Digest: JvtRKZaenYrldbXmhhStGw== Name: com/markcrocker/thoughtworks/Dates.class Digest-Algorithms: SHA MD5 SHA-Digest: KP3HSi+NRIrSkR4jmb95kIjaUn0= MD5-Digest: 8GnW+Ar10NbuR2nBZo23UQ== Name: com/markcrocker/thoughtworks/MyDate.class Digest-Algorithms: SHA MD5 SHA-Digest: xpabKMUyUDF2zZ+8iGshdlPqxz4= MD5-Digest: jVKk4iQoXwK4hgkdhX3tCA== Name: com/markcrocker/thoughtworks/TestMyDate.class Digest-Algorithms: SHA MD5 SHA-Digest: P1DQj+wS7TrFSuzeDWjl80OuiVc= MD5-Digest: qa4SavIN8HVix7eHKsAMoA== Name: com/markcrocker/thoughtworks/testFile.txt Digest-Algorithms: SHA MD5 SHA-Digest: wm4II7czUcACvCvhGAcXjLERov8= MD5-Digest: Y5DNLIqkJS+R0s2LStLJ+g== Name: com/markcrocker/thoughtworks/testfile.txt~ Digest-Algorithms: SHA MD5 SHA-Digest: /Uhndm9WuuC3hueOIeDUhaWWr9A= MD5-Digest: kyPROHXsO+HP1mXUf28M1w== Name: com/markcrocker/thoughtworks/source/BadDateException.java Digest-Algorithms: SHA MD5 SHA-Digest: dkAQjYgvIsqw7NBWvQ2UD7UrKac= MD5-Digest: 9iNzAj46BRlcBX1XroJ6AQ== Name: com/markcrocker/thoughtworks/source/Dates.java Digest-Algorithms: SHA MD5 SHA-Digest: 7dWRrrpzg+WEj0OkVUkJi8dzEl4= MD5-Digest: lC7i/J8MSZqWNmfu1ZNb/w== Name: com/markcrocker/thoughtworks/source/MyDate.java Digest-Algorithms: SHA MD5 SHA-Digest: z29V9X/K7bYCwPFFFm+NVN98QBg= MD5-Digest: Wp575woPzkqtxkDM2W8DCQ== Name: com/markcrocker/thoughtworks/source/TestMyDate.java Digest-Algorithms: SHA MD5 SHA-Digest: VoSdh4lhVpZr3EaBPDlZ97r5X4M= MD5-Digest: TJRkK9HGbev132vYam4wUA== Name: com/markcrocker/thoughtworks/doc/AllNames.html Digest-Algorithms: SHA MD5 SHA-Digest: GhIpDUEtFWVNoon5S6C++tgqrg4= MD5-Digest: irFeu1YoZ5IxCMPyjyMS0Q== Name: com/markcrocker/thoughtworks/doc/BadDateException.java.html Digest-Algorithms: SHA MD5 SHA-Digest: wgL/S3pPaOLa7EdsHHRnZZ9jOtU= MD5-Digest: A4PgvYP3n16pV7fd6Lsrog== Name: com/markcrocker/thoughtworks/doc/Dates.java.html Digest-Algorithms: SHA MD5 SHA-Digest: sK+nTGAxIu6VgXbVUXg7Iki4OFs= MD5-Digest: LICY5jXge0vQJWxdDXR0zQ== Name: com/markcrocker/thoughtworks/doc/Dates.pl Digest-Algorithms: SHA MD5 SHA-Digest: 3xnw7hCeeGERGWxzc6v7UM+CvCc= MD5-Digest: W96Wqctptbs/iRXl2djFYw== Name: com/markcrocker/thoughtworks/doc/MyDate.java.html Digest-Algorithms: SHA MD5 SHA-Digest: vQSIBBCEPK+o3MiJFEjCP8fxZlw= MD5-Digest: M62uA6nlvFPdO6PNFMORMg== Name: com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.BadDateException.html Digest-Algorithms: SHA MD5 SHA-Digest: IJB8SOLPcm33rq2kw/wyJi28p0U= MD5-Digest: GcYI7LShvOdRmuFUp92SfA== Name: com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.Dates.html Digest-Algorithms: SHA MD5 SHA-Digest: FdLcy1rmN0SVsfO+BkC+sftZQQE= MD5-Digest: 2PD0zMFqX6GkuOqKdvKaSg== Name: com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.MyDate.html Digest-Algorithms: SHA MD5 SHA-Digest: uZQ70VNgndwJGTLOX5w9pnlJ4ew= MD5-Digest: ewb1Tn75Av3eABlyd8z2+A== Name: com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.TestMyDate.html Digest-Algorithms: SHA MD5 SHA-Digest: EirrPkXlug6txbeP+o24E3QN26M= MD5-Digest: G/gMee7Wtja1SENOBfM+vQ== Name: com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.html Digest-Algorithms: SHA MD5 SHA-Digest: 3/QFoX4m6yK9xsRGjh79K981IwA= MD5-Digest: JXMcf4w9qKcJB+9LXBPzHg== Name: com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.source.html Digest-Algorithms: SHA MD5 SHA-Digest: g9+DlJhvejvJJ/QX8uQfV7iYQ+I= MD5-Digest: NtC8TzUFmL/baIcOl18g3w== Name: com/markcrocker/thoughtworks/doc/TestMyDate.java.html Digest-Algorithms: SHA MD5 SHA-Digest: RaxxRKYO0F/qmkWkbqrnbU4GGv8= MD5-Digest: LGsrr0JwdAC/0zY9J7zihg== Name: com/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.BadDateException.html Digest-Algorithms: SHA MD5 SHA-Digest: DqAiDRxWX9dn83MvD31WeuV2S5M= MD5-Digest: i1oSJ0FfjRRjP5naJYqtbw== Name: com/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.Dates.html Digest-Algorithms: SHA MD5 SHA-Digest: M42XsLVu5/3B0/bN7SmPXPRd37A= MD5-Digest: AfcFezjXf8gNqxTcY+vQyw== Name: com/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.MyDate.html Digest-Algorithms: SHA MD5 SHA-Digest: hdKiQBkz1gJwt6XT0ZF/Rl3lCL8= MD5-Digest: r4snfoGxQ7F7VEF2/inJpg== Name: com/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.TestMyDate.html Digest-Algorithms: SHA MD5 SHA-Digest: PGYON+uTzfjOteFQxHC0cGV6GDg= MD5-Digest: GEIZGLJRHllE8uCDUW+xoQ== Name: com/markcrocker/thoughtworks/doc/dates.pl.html Digest-Algorithms: SHA MD5 SHA-Digest: 1s8xUmEwcCj2CqqMYdYiG2cp7LI= MD5-Digest: rHdARcOvi5OGDTPav9WhwQ== Name: com/markcrocker/thoughtworks/doc/index.html Digest-Algorithms: SHA MD5 SHA-Digest: ZMWNTHPPWUmvJjylmgZWBMAzFbQ= MD5-Digest: bqbbn/0xQ8o8FewwYwRxgw== Name: com/markcrocker/thoughtworks/doc/packages.html Digest-Algorithms: SHA MD5 SHA-Digest: OrEfCv8CxzdnZyEBOC12fh0JQOs= MD5-Digest: Aj8knK/4oCzaA66W8+Sd0g== Name: com/markcrocker/thoughtworks/doc/tree.html Digest-Algorithms: SHA MD5 SHA-Digest: /6j4hD9ruKKXl5WKtk2VzctFH+k= MD5-Digest: ALvMrKxLhqQZtbosY04d6Q== PK !<&)3com/markcrocker/thoughtworks/BadDateException.class-+$%&'        # ( ) * ()Ljava/lang/String;()V&(Ljava/lang/Object;)Ljava/lang/String;,(Ljava/lang/String;)Ljava/lang/StringBuffer;(Ljava/lang/String;)VBadDateException.javaCode ConstantValueDate out of range or malformed ExceptionsLineNumberTableLjava/lang/String;LocalVariables SourceFileappend-com/markcrocker/thoughtworks/BadDateExceptionjava/lang/Exceptionjava/lang/Stringjava/lang/StringBufferstandardMessagetoStringvalueOf! ( $*  :*Y  +  "    "PK !<&))$/(com/markcrocker/thoughtworks/Dates.class-VWjklmnopqvxy{ = = > ? @ @ @ A B C D E F G H I J K L M N O P Q R S T U rZ r_ ra re \ d g ` Z f b X Y } i e c ] e Y ^ Z Z [ Y is:  requested()I()Ljava/lang/String;()V()Z(I)Ljava/lang/StringBuffer;(I)V(II)Ljava/lang/String;(III)V((Lcom/markcrocker/thoughtworks/MyDate;)I(Ljava/io/Reader;)V(Ljava/lang/Object;)Z(Ljava/lang/String;)I,(Ljava/lang/String;)Ljava/lang/StringBuffer;(Ljava/lang/String;)V(Ljava/lang/String;)Z(Z)Ljava/lang/StringBuffer;([Ljava/lang/String;)V;([Ljava/lang/String;I)Lcom/markcrocker/thoughtworks/MyDate;, --exceptions--help--test-e-f-h-tCode ConstantValue Dates.java!Exception test mode flag detected ExceptionsFile input from file Help mode flag detectedILine LineNumberTableLjava/io/PrintStream;LocalVariables SourceFileSyntax: Dates MM, DD, YYYY, mm, dd, yyyy Dates -f inputFile Dates [-t|--test|-e|--exceptions|-h|--help] Where: MM and mm represent month numbers from 1-12. DD and dd represent day of the month numbers from 1-28, 29, 30 or 31 depending on the month. YYYY and yyyy represent year numbers from 1900-2099, inclusive. The first case produces the number of days between the two dates. The second case reads dates in the same format as in case on from file inputFile. The third case produces test output, exception test output or this message. These switches may be used in combination with each other and multiple times. Test mode flag detectedTests passed = appendbetweenclose-com/markcrocker/thoughtworks/BadDateException"com/markcrocker/thoughtworks/Dates#com/markcrocker/thoughtworks/MyDate'com/markcrocker/thoughtworks/TestMyDate debugLevelendsWithequalsjava/io/BufferedReaderjava/io/FileNotFoundExceptionjava/io/FileReaderjava/io/IOExceptionjava/io/PrintStreamjava/lang/Integerjava/lang/Objectjava/lang/Stringjava/lang/StringBufferjava/lang/Systemjava/util/StringTokenizerlengthmain nextTokenout parseDates parseFileparseIntprintlnreadLine substring syntaxMessagetestDateExceptionstestStandardDatestoString!z isN*d*2-*`2-y*2*2/d846*2*2/d846*`2-*2*2/d84=*2*2/84=Yld#N-|2 ! "#"%6&M(Z)p(s+.0w es<YY*%$NY":6$1Y&())<6 Y'M,0:/d846,0:/d846,0:/d846 ,0:/d846 ,0:/d846 ,0:46 Y ld#: Y ld  #:1 +5-7Y:-,|j>@ABC!D$EJFTGZHlIrJKLMNOPQRTUW CY;w Zs- 16|`k`_ hs<*9=*2 .*2.+ 161Y&;*<6*2.*2. 1 6:*2 .*2. 1 69s*d>*2.3"1Y &*`2))<6*230*2YN"*`2Y:1-+59*|"suv u xyz'{4|LyO}Z~eru}x  xpwrZs*!|uPK !<&)i9)com/markcrocker/thoughtworks/MyDate.class-h234@ABCNUVZ[\]^_ " # # $ % & ' ( ) * + , - . / 0 1 E7 E? R8 S: S> WJ XJ Y5 `J aJ bQ cQ dL e? g6 g9 day =  month =  where Month = ()I()Ljava/lang/String;()V(I)I(I)Ljava/lang/String;(I)Ljava/lang/StringBuffer;(I)V(III)V((Lcom/markcrocker/thoughtworks/MyDate;)I,(Ljava/lang/String;)Ljava/lang/StringBuffer;(Ljava/lang/String;)V)) or Month (= -->Error in Day (= -->Error in Year (= Code ConstantValue Deprecated ExceptionsILineNumberTableLjava/io/PrintStream;LocalVariables(MyData instance constructed with year =  MyDate.java SourceFile[Iabsappendbetween-com/markcrocker/thoughtworks/BadDateException#com/markcrocker/thoughtworks/MyDatedate debugLevelgetDatejava/io/PrintStreamjava/lang/Integerjava/lang/Mathjava/lang/Objectjava/lang/StringBufferjava/lang/System leapMonth leapOffset monthLength monthOffsetoutprintln setDebugLeveltoString!  bQ cQ`JaJXJWJE<F **+Y ǣ  ) YY *p8*dl* **Y` *ld.*`) YY *d.`*`mh`K!$%4(8)?*D+J,[-d.i-l,p4u5{6769;<;=>5AEFGHIHGN $I Y5F*KVf;F"*K ]\Hg6F *!KdT=F;*+dd==KklmnD7F YOYOYOYOYOYOYOYOYOY OY OY O YOY;OYZOYxOYOYOYOYOY OY 0OY NOKIPOPK "<&),QQ-com/markcrocker/thoughtworks/TestMyDate.class-WPQRSTUVWXfghijkoqstuv{|}~ )? &@ +A +B +C +D &E *F ,G ,H ,I -J (K 'L 'M 'N +O lZ l^ lc \ b d _ a x ] x ` c Z Z [ Y- Test failed: result should have been 0 days* Days between 1, 1, 1900 and 12, 31, 2099.( Days between 1, 3, 1989 and 3, 8, 1983.( Days between 1, 3, 1989 and 8, 3, 1983.) Days between 6, 2, 1983 and 6, 22, 1983.* Days between 7, 4, 1984 and 12, 25, 1984.( Days between 9, 3, 2000 and 9, 3, 2000.( Days between 9, 3, 2000 and 9, 4, 2000.( Days between 9, 3, 2000 and 9, 5, 2000.()Ljava/lang/String;()V()Z(I)Ljava/lang/StringBuffer;(I)V(III)V((Lcom/markcrocker/thoughtworks/MyDate;)I(Ljava/io/PrintStream;)V(Ljava/lang/Object;)Z,(Ljava/lang/String;)Ljava/lang/StringBuffer;(Ljava/lang/String;)V(Z)Ljava/lang/StringBuffer;([Ljava/lang/String;)V --exceptions--help--test-e-h-tCode ConstantValue!Exception test mode flag detected ExceptionsHelp mode flag detectedILine #1: There are Line #2: There are Line #3a: There are Line #3b: There are LineNumberTableLjava/io/PrintStream;LocalVariables SourceFileSyntax: TestMyDate [-t|--test|-e|--exceptions|-h|--help] Produces test output, exception test output or this message. These switches may be used in combination with each other and multiple times. Test #4: There are Test #5: There are Test #6: There are Test #7: There are +Test failed: result should have been 0 days+Test failed: result should have been 1 days-Test failed: result should have been 173 days,Test failed: result should have been 19 days.Test failed: result should have been 1979 days.Test failed: result should have been 2127 days/Test failed: result should have been 73047 daysTest mode flag detectedTestMyDate.javaTests passed = appendbetween-com/markcrocker/thoughtworks/BadDateException#com/markcrocker/thoughtworks/MyDate'com/markcrocker/thoughtworks/TestMyDate debugLevelequalserrexitjava/io/PrintStreamjava/lang/Objectjava/lang/Stringjava/lang/StringBufferjava/lang/Systemjava/lang/ThrowablemainoutprintStackTraceprintln syntaxMessagetestDateExceptionstestStandardDatestoString!')r[m;&YS/L&YS/M,+4>8+Y012>: ;8:&YT/:&YT /:4>8+Y012>: ;8:&YY/:&YS/:4>8+Y012>: ;8 :&YY/:&YS/:  4>8+Y012>:O ;8!:&Yd /: &Yd /:   4>8+Y01 2>: ;8:&Yd /: &Yd /:   4>8+Y01 2>: ;8:&Yd /:&Yd /:4>8+Y012>: ;8:&Y/:&Y /:4>8+Y012>:;8":L+697tw%w?#>DFN\k s!"#$'()*+,-01 23,43556=9K:Y;a<|=>?BCDEFGHKLMNOPQ%T1UAVIWdXjYlZtw]x^_bZmH&/ K*69&g/ K*69&S/ K*69&S / K*69&S/ K*69&S"/ K*69&T/ K*69&S/K*69 %!$%,69%ALO%Wcf%nz}%%%wFjkl$m,n9oApOqWrfsnt}uvwxyi Zm- 8:w em#<*;=*25*2 5+ 8#:8+Y$0=3>:Y*25*2 5 8:<0*25*2 5 8:;;*fwb '4LOZeruxp%lZm*.w zPK ]S&)w)com/markcrocker/thoughtworks/testFile.txt6, 2, 1983, 6, 22, 1983 7, 4, 1984, 12, 25, 1984 1, 3, 1989, 8, 3, 1983 1, 3, 1989, 3, 8, 1983 2, 28, 2000, 3, 1, 2000 1, 1, 1900, 12, 31, 2099 PK k#) 1cc*com/markcrocker/thoughtworks/testfile.txt~6, 2, 1983, 6, 22, 1983 7, 4, 1984, 12, 25, 1984 1, 3, 1989, 8, 3, 1983 1, 3, 1989, 3, 8, 1983 PK 9&)9com/markcrocker/thoughtworks/source/BadDateException.java//: BadDateException.java /** Simple Exception class for MyDates class * @author Mark Crocker * @author http://www.markcrocker.com/ * @version 0.93 */ package com.markcrocker.thoughtworks; public class BadDateException extends Exception { private static String standardMessage = "Date out of range or malformed"; /** Default exception method for BadDateException */ public BadDateException() { super(standardMessage); } /** Message version of BadDateException method * @param msg Extra message to be provided along with the standard * BadDateException message. */ public BadDateException(String msg) { super(standardMessage + "\n" + msg); } } ///:~ PK 9&)[.com/markcrocker/thoughtworks/source/Dates.java//: Dates.java /** Simple date calculation program that uses the MyDate class to calculate * the number of days between two given dates. * @author Mark Crocker * @author http://www.markcrocker.com/~mcrocker/ * @version 0.96 */ package com.markcrocker.thoughtworks; import java.io.*; import java.util.*; import javax.swing.*; public class Dates { private int debugLevel = 0; // vestigal 1960s style debugging tool /** parseDates. Converts an array of strings into a MyDate * object. Input format is VERY fussy. Expects * @param args is a string array of at least three elements. The elements starting at the indicated index should be MM, DD, YYYY[,] respectively. * @param i is the array index where the strings defining the date start. * @exception BadDateException via MyDate constructor. * @return Initialized MyDate object. */ // May actually be better placed as a constructor in MyDate class. private static MyDate parseDates(String[] args, int i) throws BadDateException { int year; MyDate date = null; if ((args.length - i > 2) && (args[i].endsWith(",")) && (args[i+1].endsWith(",")) ) { // Need at least three terms, two ending in commas int month = Integer.parseInt(args[i].substring(0,args[i].length()-1)); int day = Integer.parseInt(args[++i].substring(0,args[i].length()-1)); if (args[i+1].endsWith(",")) { // Last term may or may not have a comma year = Integer.parseInt(args[++i].substring(0,args[i].length()-1)); // ignore comma } else { year = Integer.parseInt(args[++i].substring(0,args[i].length())); // no comma } date = new MyDate(year-1900,month,day); } return date; } /** parseFile. Converts a file with pairs of dates on each line * into dates and prints out the number of days * between the two dates. The date format is VERY fussy. * Each date should be in the format MM, DD, YYYY[,]. * @param fileName is the file that data data is to be read from. * @exception BadDateException via MyDate constructors */ private static void parseFile(String fileName) throws FileNotFoundException, IOException, BadDateException { int debugLevel = 0; // vestigal 1960s style debugging tool StringTokenizer st; BufferedReader in = new BufferedReader( new FileReader(fileName)); String line = new String(); int lineNo = 0; while((line = in.readLine())!= null) { lineNo++; if (debugLevel > 1) { System.out.println ("Line " + lineNo + " is: " + line); } st = new StringTokenizer(line); String token = st.nextToken(); int startMonth = Integer.parseInt(token.substring(0,token.length()-1)); token = st.nextToken(); int startDay = Integer.parseInt(token.substring(0,token.length()-1)); token = st.nextToken(); int startYear = Integer.parseInt(token.substring(0,token.length()-1)); token = st.nextToken(); int endMonth = Integer.parseInt(token.substring(0,token.length()-1)); token = st.nextToken(); int endDay = Integer.parseInt(token.substring(0,token.length()-1)); token = st.nextToken(); int endYear = Integer.parseInt(token); MyDate startDate = new MyDate(startYear-1900,startMonth,startDay); MyDate endDate = new MyDate(endYear-1900,endMonth,endDay); System.out.println( endDate.between(startDate)); } in.close(); } /** syntaxMessage. Prints out syntax/help message. */ private static void syntaxMessage() { System.out.println("Syntax:\n" + " Dates MM, DD, YYYY, mm, dd, yyyy\n" + " Dates -f inputFile\n" + " Dates [-t|--test|-e|--exceptions|-h|--help]\n" + " Where: MM and mm represent month numbers from 1-12.\n" + " DD and dd represent day of the month numbers\n" + " from 1-28, 29, 30 or 31 depending on the month.\n" + " YYYY and yyyy represent year numbers from 1900-2099, inclusive.\n" + " The first case produces the number of days between the two dates.\n" + " The second case reads dates in the same format as in case on from\n" + " file inputFile.\n" + " The third case produces test output, exception test output or this message.\n" + " These switches may be used in combination with each other and multiple times.\n"); } public static void main(String[] args) throws FileNotFoundException, IOException, BadDateException { int debugLevel = 0; // vestigal 1960s style debugging tool if (args.length < 1) { syntaxMessage(); } else { for (int i = 0; i < args.length; i++) { // go through all args if ( args[i].equals("-t") || args[i].equals("--test")) { if (debugLevel > 1) { System.out.println("Test mode flag detected"); } System.out.println("Tests passed = " + TestMyDate.testStandardDates()); } else if ( args[i].equals("-e") || args[i].equals("--exceptions")) { if (debugLevel > 1) { System.out.println("Exception test mode flag detected"); } TestMyDate.testDateExceptions(); } else if ( args[i].equals("-h") || args[i].equals("--help")) { if (debugLevel > 1) { System.out.println("Help mode flag detected"); } syntaxMessage(); } else if ( (args.length - i > 1) && (args[i].equals("-f")) ) { if (debugLevel > 1) { System.out.println("File input from file " + args[i+1] + " requested"); } parseFile(args[++i]); } else { MyDate startDate; MyDate endDate; if (((startDate = parseDates(args, i)) != null) && ((endDate = parseDates(args, i+3)) != null)) { System.out.println( endDate.between(startDate)); i += 5; } else { // not a valid input, so spit out a syntax message. syntaxMessage(); break; } } } } } } ///:~ /* Todo ------- 1. Command line input: a. No input starts GUI. b. Switches: iii) Debug Level. 2. More sophisticated input parsing: a. Allow for no spaces between fields. b. Enforce comma when multiple dates are entered, but not last one. 4. Deal with 1986 vs. 86 issue. 5. Add exception catching to parseDates. 6. Consolodate parsing into a single core routine and share with both parsing methods. 7. Create GUI version. 8. Beanify for use in JSP. 9. Create applet version. 10. Move parseDates to MyDates as a constructor? 11. Change file parser to use StreamTokenizer: a. Allows use of comments in input file. */ PK ;&)T/com/markcrocker/thoughtworks/source/MyDate.java//: MyDate.java /** Simple date class * @author Mark Crocker * @author http://www.markcrocker.com/~mcrocker/ * @version 0.96 */ package com.markcrocker.thoughtworks; import java.io.*; import java.util.*; public class MyDate { private static int[] monthLength = {31,28,31,30,31,30,31,31,30,31,30,31}; // Number of days in each month. private static int[] monthOffset = {0,31,59,90,120,151,181,212,243,273,304,334}; // Number of days in year prior to current month private int leapMonth; // The number of days to add to the date to // accomodate the leap day in this year. Depends // on whether month is after February or not. private int leapOffset; // The number of days to add for all the // leap days in the previous years. private int debugLevel = 0; // Vestigal 1960s style debugging tool. private int date; // Date as the number of days since 1900-Jan-01 /** MyDate primary constructor. Converts date to an internal format for * storage and checks for invalid or out of range dates. * @param year year past 1900 (0-199). Ex: 1981 will be year 81, 2009 is 109. * @param month month of the year (1-12). * @param day day of the month (1-28,29,30, or 31) depending on the month. * @exception BadDateException thrown if the date is malformed or out of range. */ MyDate(int year, int month, int day) throws BadDateException { if (debugLevel > 2) { System.out.println("MyData instance constructed with year = " + year + " month = " + month + " day = " + day); } /* First check for valid year and month. These are fixed, so its an easy check */ if ((year < 0) || (year > 199) || (month < 1) || (month > 12)) { throw new BadDateException("-->Error in Year (= " + year + ") or Month (= " + month + ")"); } /* Before checking for valid day, need to figure out leap days. * Also take advantage of the logic to do the leap day offset * calculation.*/ leapMonth = 0; // Default. if (year%4 == 0) { // Is it a leap year? if (year > 4) { // Dont need previous years leap days until 1905 leapOffset = (year-1)/4; // Leap days for all previous years. } else { leapOffset = 0; } if (month == 2) { // Is it February? leapMonth = 1; } else if (month > 2) { // Is it after February? leapOffset += 1; // Can count leap day of this year. } // Must be January, nothing else required. } else { // NOT a leap year. leapOffset = year/4; // Leap days for all previous years, this one doesnt have one. } /* Check for valid day using leapMonth info */ if ((day < 1) || (day > monthLength[month-1] + leapMonth)) { throw new BadDateException("-->Error in Day (= " + day + " where Month = " + month + ")"); } /* Finally, decode date into internal format (ie: an integer * representing the number of days since 1900-Jan-01). */ date = day + monthOffset[month-1] + leapOffset + year*365; // Actual date calculation. } /** getDate. Mostly used in calculating date arimthmatic. * @return Returns date as the number of days since 1900-Jan-01. */ public int getDate() { return date; } /** setDebugLevel. Sets debugLevel variable for 1960s style debugging. * @deprecated Only used during code development. */ public void setDebugLevel(int dLevel) { debugLevel = dLevel; } /** toString. Java default string converter. * @return Returns date as a string that represents the number of days since 1900-Jan-01. */ public String toString() { return Integer.toString(date); } /** between. Calculates the number of days between two dates. Commutative and exclusive. * @return Returns number of days between two dates (exclusive). */ public int between(MyDate someOtherDate) { int between = Math.abs(date - someOtherDate.getDate())-1; // basic calculation. if (between < 0) // have to watch for case where the two dates are the same. between = 0; return between; } } ///:~ /* Todo ------- 1. Change date range from 0-199 to 1900-2099. */ PK >&)363com/markcrocker/thoughtworks/source/TestMyDate.java//: TestMyDate.java /** Tests used to verify MyDates class. * @author Mark Crocker * @author http://www.markcrocker.com/~mcrocker/ * @version 0.92 */ package com.markcrocker.thoughtworks; public class TestMyDate { private int debugLevel = 0; // vestigal 1960s style debugging tool /** testStandardDates. Basic tests of MyDate class using several known dates, * comparing the number of days between and verifying the answers. * @return testPassed. True if all tests were passed, false otherwise. */ static boolean testStandardDates() { boolean testPassed = true; try { MyDate start1 = new MyDate(83,6,2); MyDate end1 = new MyDate(83,6,22); int daysBetween = end1.between(start1); System.out.println("Line #1: There are " + daysBetween + " Days between 6, 2, 1983 and 6, 22, 1983."); if (daysBetween != 19) { testPassed = false; System.out.println("Test failed: result should have been 19 days"); } MyDate start2 = new MyDate(84,7,4); MyDate end2 = new MyDate(84,12,25); daysBetween = end2.between(start2); System.out.println("Line #2: There are " + daysBetween + " Days between 7, 4, 1984 and 12, 25, 1984."); if (daysBetween != 173) { testPassed = false; System.out.println("Test failed: result should have been 173 days"); } MyDate start3a = new MyDate(89,1,3); MyDate end3a = new MyDate(83,8,3); daysBetween = end3a.between(start3a); System.out.println("Line #3a: There are " + daysBetween + " Days between 1, 3, 1989 and 8, 3, 1983."); if (daysBetween != 1979) { testPassed = false; System.out.println("Test failed: result should have been 1979 days"); } MyDate start3b = new MyDate(89,1,3); MyDate end3b = new MyDate(83,3,8); daysBetween = end3b.between(start3b); System.out.println("Line #3b: There are " + daysBetween + " Days between 1, 3, 1989 and 3, 8, 1983."); if (daysBetween != 2127) { testPassed = false; System.out.println("Test failed: result should have been 2127 days"); } MyDate start4 = new MyDate(100,9,3); MyDate end4 = new MyDate(100,9,5); daysBetween = end4.between(start4); System.out.println("Test #4: There are " + daysBetween + " Days between 9, 3, 2000 and 9, 5, 2000."); if (daysBetween != 1) { testPassed = false; System.out.println("Test failed: result should have been 1 days"); } MyDate start5 = new MyDate(100,9,3); MyDate end5 = new MyDate(100,9,4); daysBetween = end5.between(start5); System.out.println("Test #5: There are " + daysBetween + " Days between 9, 3, 2000 and 9, 4, 2000."); if (daysBetween != 0) { testPassed = false; System.out.println("Test failed: result should have been 0 days"); } MyDate start6 = new MyDate(100,9,3); MyDate end6 = new MyDate(100,9,3); daysBetween = end6.between(start6); System.out.println("Test #6: There are " + daysBetween + " Days between 9, 3, 2000 and 9, 3, 2000."); if (daysBetween != 0) { testPassed = false; System.out.println(" Test failed: result should have been 0 days"); } MyDate start7 = new MyDate(00,1,1); MyDate end7 = new MyDate(199,12,31); daysBetween = end7.between(start7); System.out.println("Test #7: There are " + daysBetween + " Days between 1, 1, 1900 and 12, 31, 2099."); if (daysBetween != 73047) { testPassed = false; System.out.println("Test failed: result should have been 73047 days"); } } catch(BadDateException e) { // shouldnt generate any exceptions because input is fixed. e.printStackTrace(System.err); System.exit(1); } return testPassed; } /** testDateExceptions. Tests of MyDate class exceptions. Checks * to make sure that known bad dates are caught by the constructor * checking algorithms. Does not verify results... yet. */ static void testDateExceptions() { try { MyDate badYear1 = new MyDate(-83,6,2); } catch(BadDateException e) { e.printStackTrace(System.err); } try { MyDate badYear2 = new MyDate(103,6,2); } catch(BadDateException e) { e.printStackTrace(System.err); } try { MyDate badMonth1 = new MyDate(83,0,2); } catch(BadDateException e) { e.printStackTrace(System.err); } try { MyDate badMonth2 = new MyDate(83,13,2); } catch(BadDateException e) { e.printStackTrace(System.err); } try { MyDate badDay1 = new MyDate(83,6,-4); } catch(BadDateException e) { e.printStackTrace(System.err); } try { MyDate badDay2 = new MyDate(83,6,34); } catch(BadDateException e) { e.printStackTrace(System.err); } try { MyDate badDay3 = new MyDate(84,2,29); // actually a good date, shouldnt produce an exception } catch(BadDateException e) { e.printStackTrace(System.err); } try { MyDate badDay3 = new MyDate(83,2,29); } catch(BadDateException e) { e.printStackTrace(System.err); } } /** syntaxMessage. Prints out syntax/help message. */ private static void syntaxMessage() { System.out.println("Syntax:\n" + " TestMyDate [-t|--test|-e|--exceptions|-h|--help]\n" + " Produces test output, exception test output or this message.\n" + " These switches may be used in combination with each other and multiple times.\n"); } public static void main(String[] args) throws BadDateException { int debugLevel = 0; // vestigal 1960s style debugging tool if (args.length < 1) { syntaxMessage(); } else { for (int i = 0; i < args.length; i++) { // go through all args if ( args[i].equals("-t") || args[i].equals("--test")) { if (debugLevel > 1) { System.out.println("Test mode flag detected"); } System.out.println("Tests passed = " + testStandardDates()); } else if ( args[i].equals("-e") || args[i].equals("--exceptions")) { if (debugLevel > 1) { System.out.println("Exception test mode flag detected"); } testDateExceptions(); } else if ( args[i].equals("-h") || args[i].equals("--help")) { if (debugLevel > 1) { System.out.println("Help mode flag detected"); } syntaxMessage(); } else { // not a valid input, so spit out a syntax message. syntaxMessage(); break; } } } } } ///:~ /* Todo ------- 1. Add verification to exception testing routine. */ PK /<&)@!!.com/markcrocker/thoughtworks/doc/AllNames.html Index of all Fields and Methods
All Packages  Class Hierarchy

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Index of all Fields and Methods

B

BadDateException(). Constructor for class com.markcrocker.thoughtworks.BadDateException
Default exception method for BadDateException
BadDateException(String). Constructor for class com.markcrocker.thoughtworks.BadDateException
Message version of BadDateException method
between(MyDate). Method in class com.markcrocker.thoughtworks.MyDate
between.

D

date. Variable in class com.markcrocker.thoughtworks.MyDate
Dates(). Constructor for class com.markcrocker.thoughtworks.Dates
debugLevel. Variable in class com.markcrocker.thoughtworks.Dates
debugLevel. Variable in class com.markcrocker.thoughtworks.MyDate
debugLevel. Variable in class com.markcrocker.thoughtworks.TestMyDate

G

getDate(). Method in class com.markcrocker.thoughtworks.MyDate
getDate.

L

leapMonth. Variable in class com.markcrocker.thoughtworks.MyDate
leapOffset. Variable in class com.markcrocker.thoughtworks.MyDate

M

main(String[]). Static method in class com.markcrocker.thoughtworks.Dates
main(String[]). Static method in class com.markcrocker.thoughtworks.TestMyDate
monthLength. Static variable in class com.markcrocker.thoughtworks.MyDate
monthOffset. Static variable in class com.markcrocker.thoughtworks.MyDate
MyDate(int, int, int). Constructor for class com.markcrocker.thoughtworks.MyDate
MyDate primary constructor.

P

parseDates(String[], int). Static method in class com.markcrocker.thoughtworks.Dates
parseDates.
parseFile(String). Static method in class com.markcrocker.thoughtworks.Dates
parseFile.

S

setDebugLevel(int). Method in class com.markcrocker.thoughtworks.MyDate
setDebugLevel.
standardMessage. Static variable in class com.markcrocker.thoughtworks.BadDateException
syntaxMessage(). Static method in class com.markcrocker.thoughtworks.Dates
syntaxMessage.
syntaxMessage(). Static method in class com.markcrocker.thoughtworks.TestMyDate
syntaxMessage.

T

testDateExceptions(). Static method in class com.markcrocker.thoughtworks.TestMyDate
testDateExceptions.
TestMyDate(). Constructor for class com.markcrocker.thoughtworks.TestMyDate
testStandardDates(). Static method in class com.markcrocker.thoughtworks.TestMyDate
testStandardDates.
toString(). Method in class com.markcrocker.thoughtworks.MyDate
toString.
PK =&)T:#5 5 ;com/markcrocker/thoughtworks/doc/BadDateException.java.html baddateexception.java
//: BadDateException.java

/** Simple Exception class for MyDates class
  * @author Mark Crocker <mcrocker@micron.net>
  * @author http://www.markcrocker.com/
  * @version 0.93
  */

package com.markcrocker.thoughtworks;

public class BadDateException extends Exception {

    private static String standardMessage = "Date out of range or malformed";


    /** Default exception method for BadDateException
      */
    public BadDateException() {
	super(standardMessage);
    }


    /** Message version of BadDateException method
      * @param msg Extra message to be provided along with the standard 
      *            BadDateException message.
      */
    public BadDateException(String msg) {
        super(standardMessage + "\n" + msg);
    }


} ///:~

PK I&)/d770com/markcrocker/thoughtworks/doc/Dates.java.html dates.java
//: Dates.java

/** Simple date calculation program that uses the MyDate class to calculate
  * the number of days between two given dates.
  * @author Mark Crocker <mcrocker@micron.net>
  * @author http://www.markcrocker.com/~mcrocker/
  * @version 0.96
  */

package com.markcrocker.thoughtworks;

import java.io.*;
import java.util.*;
import javax.swing.*;


public class Dates {
    private int debugLevel = 0;  // vestigal 1960s style debugging tool


    /** parseDates.  Converts an array of strings into a MyDate
      *              object.  Input format is VERY fussy.  Expects
      * @param args is a string array of at least three elements.  The elements starting at the indicated index should be MM, DD, YYYY[,] respectively.
      * @param i is the array index where the strings defining the date start.
      * @exception BadDateException via MyDate constructor.
      * @return Initialized MyDate object.
      */
    // May actually be better placed as a constructor in MyDate class.
    private static MyDate parseDates(String[] args, int i) throws BadDateException {
	int year;
	MyDate date = null;
	
	if ((args.length - i > 2) && 
	    (args[i].endsWith(",")) &&
	    (args[i+1].endsWith(",")) ) {  // Need at least three terms, two ending in commas
	    
	    int month = Integer.parseInt(args[i].substring(0,args[i].length()-1));
	    int day   = Integer.parseInt(args[++i].substring(0,args[i].length()-1));
	    
	    if (args[i+1].endsWith(",")) { // Last term may or may not have a comma
		year  = Integer.parseInt(args[++i].substring(0,args[i].length()-1)); // ignore comma
	    } else {
		year  = Integer.parseInt(args[++i].substring(0,args[i].length()));   // no comma
	    }
	    
	    date = new MyDate(year-1900,month,day);
	}
	return date;
    }


    /** parseFile.  Converts a file with pairs of dates on each line
      *             into dates and prints out the number of days
      *             between the two dates.  The date format is VERY fussy.
      *             Each date should be in the format MM, DD, YYYY[,].
      * @param fileName is the file that data data is to be read from.
      * @exception BadDateException via MyDate constructors
      */
    private static void parseFile(String fileName) throws FileNotFoundException, 
                                                          IOException, 
							  BadDateException {
	int debugLevel = 0;  // vestigal 1960s style debugging tool
	StringTokenizer st;
	BufferedReader in = new BufferedReader( new FileReader(fileName));
	String line = new String();
	int lineNo = 0;
	while((line = in.readLine())!= null) {
	    lineNo++;
	    if (debugLevel > 1) { System.out.println ("Line " + lineNo + " is: " + line); }
	    st = new StringTokenizer(line);
       	    String token = st.nextToken();
	    int startMonth = Integer.parseInt(token.substring(0,token.length()-1));
	    token = st.nextToken();
	    int startDay   = Integer.parseInt(token.substring(0,token.length()-1));
	    token = st.nextToken();
	    int startYear  = Integer.parseInt(token.substring(0,token.length()-1));
	    token = st.nextToken();
	    int endMonth   = Integer.parseInt(token.substring(0,token.length()-1));
	    token = st.nextToken();
	    int endDay     = Integer.parseInt(token.substring(0,token.length()-1));
	    token = st.nextToken();
	    int endYear    = Integer.parseInt(token);
		    
	    MyDate startDate = new MyDate(startYear-1900,startMonth,startDay);
	    MyDate endDate = new MyDate(endYear-1900,endMonth,endDay);
	    
	    System.out.println( endDate.between(startDate));
	}
	in.close();
    }


    /** syntaxMessage.  Prints out syntax/help message.
      */
    private static void syntaxMessage() {
	System.out.println("Syntax:\n" +
			   "    Dates MM, DD, YYYY, mm, dd, yyyy\n" +
			   "    Dates -f inputFile\n" +
			   "    Dates [-t|--test|-e|--exceptions|-h|--help]\n" +
			   " Where: MM and mm represent month numbers from 1-12.\n" +
			   "        DD and dd represent day of the month numbers\n" +
			   "          from 1-28, 29, 30 or 31 depending on the month.\n" +
			   "        YYYY and yyyy represent year numbers from 1900-2099, inclusive.\n" +
			   " The first case produces the number of days between the two dates.\n" +
			   " The second case reads dates in the same format as in case on from\n" +
			   "   file inputFile.\n" +
			   " The third case produces test output, exception test output or this message.\n" + 
			   " These switches may be used in combination with each other and multiple times.\n");
    }


    public static void main(String[] args) throws FileNotFoundException, 
                                                  IOException, 
						  BadDateException {
	int debugLevel = 0;  // vestigal 1960s style debugging tool

	if (args.length < 1) {
	    syntaxMessage();
	} else {
	    for (int i = 0; i < args.length; i++) {  // go through all args
		if ( args[i].equals("-t") || 
		     args[i].equals("--test")) {
		    if (debugLevel > 1) { System.out.println("Test mode flag detected"); }
		    System.out.println("Tests passed = " + TestMyDate.testStandardDates());
		} else if ( args[i].equals("-e") || 
			    args[i].equals("--exceptions")) {
		    if (debugLevel > 1) { System.out.println("Exception test mode flag detected"); }
		    TestMyDate.testDateExceptions();
		} else if ( args[i].equals("-h") || 
			    args[i].equals("--help")) {
		    if (debugLevel > 1) { System.out.println("Help mode flag detected"); }
		    syntaxMessage();
		} else if ( (args.length - i > 1) && 
			    (args[i].equals("-f"))  ) {
		    if (debugLevel > 1) { System.out.println("File input from file " + args[i+1] + " requested"); }
		    parseFile(args[++i]);
		} else {
		    MyDate startDate;
		    MyDate endDate;
		    if (((startDate = parseDates(args, i))   != null) && 
			((endDate   = parseDates(args, i+3)) != null))   {
			System.out.println( endDate.between(startDate));
			i += 5;
		    } else { // not a valid input, so spit out a syntax message.
			syntaxMessage();
			break;
		    }
		}
	    }
	}
    }

} ///:~


/* Todo
-------

 1. Command line input:
    a. No input starts GUI.
    b. Switches:
       iii) Debug Level.
 2. More sophisticated input parsing:
    a. Allow for no spaces between fields.
    b. Enforce comma when multiple dates are entered, but not last one.
 4. Deal with 1986 vs. 86 issue.
 5. Add exception catching to parseDates.
 6. Consolodate parsing into a single core routine and share with both parsing methods.
 7. Create GUI version.
 8. Beanify for use in JSP.
 9. Create applet version.
10. Move parseDates to MyDates as a constructor?
11. Change file parser to use StreamTokenizer:
    a. Allows use of comments in input file.

 */

PK k6&)`^^)com/markcrocker/thoughtworks/doc/Dates.plextproc perl -S # Rough perl program to calculate days between dates use HTTP::Date qw(str2time); $secondsADay = 60*60*24; $days= abs(str2time($ARGV[1])- str2time($ARGV[0]))/$secondsADay-1; print "$days Days\n"; exit; # extproc is an OS/2 trick to get the .pl to execute. # in UNIX, you need a line like #!/usr/bin/perl... PK =&)C[p&&1com/markcrocker/thoughtworks/doc/MyDate.java.html mydate.java
//: MyDate.java

/** Simple date class
  * @author Mark Crocker <mcrocker@micron.net>
  * @author http://www.markcrocker.com/~mcrocker/
  * @version 0.96
  */

package com.markcrocker.thoughtworks;

import java.io.*;
import java.util.*;

public class MyDate {
    
    private static int[] monthLength = {31,28,31,30,31,30,31,31,30,31,30,31};  
                                // Number of days in each month.
    private static int[] monthOffset = {0,31,59,90,120,151,181,212,243,273,304,334}; 
                                // Number of days in year prior to current month
    private int leapMonth;      // The number of days to add to the date to
                                // accomodate the leap day in this year.  Depends
                                // on whether month is after February or not.
    private int leapOffset;     // The number of days to add for all the
                                // leap days in the previous years.
    private int debugLevel = 0; // Vestigal 1960s style debugging tool.
    
    private int date;           // Date as the number of days since 1900-Jan-01

    /** MyDate primary constructor.  Converts date to an internal format for 
      * storage and checks for invalid or out of range dates.
      * @param year year past 1900 (0-199).  Ex: 1981 will be year 81, 2009 is 109.
      * @param month month of the year (1-12).
      * @param day day of the month (1-28,29,30, or 31) depending on the month.
      * @exception BadDateException thrown if the date is malformed or out of range.
      */
    MyDate(int year, int month, int day) throws BadDateException {
	if (debugLevel > 2) { System.out.println("MyData instance constructed with year = " + year + " month = " + month + " day = " + day); }

	/* First check for valid year and month.  These are fixed, so its an easy check */
	if ((year < 0)   ||
	    (year > 199) ||
	    (month < 1)  ||
	    (month > 12)) {
	    throw new BadDateException("-->Error in Year (= " + year +
				       ") or Month (= " + month +
				       ")");
	}

	/* Before checking for valid day, need to figure out leap days.
	 * Also take advantage of the logic to do the leap day offset
         * calculation.*/
	leapMonth = 0;                   // Default.
	if (year%4 == 0) {               // Is it a leap year?
	    if (year > 4) {              // Dont need previous years leap days until 1905
		leapOffset = (year-1)/4; // Leap days for all previous years.
	    } else {
		leapOffset = 0;
	    }
	    if (month == 2) {            // Is it February?
		leapMonth = 1;
	    } else if (month > 2) {      // Is it after February?
		leapOffset += 1;         // Can count leap day of this year.
	    }                            // Must be January, nothing else required.
	} else {                         // NOT a leap year.
	    leapOffset = year/4;         // Leap days for all previous years, this one doesnt have one.
	}

	/* Check for valid day using leapMonth info */
	if ((day < 1) ||
	    (day > monthLength[month-1] + leapMonth)) {
	    throw new BadDateException("-->Error in Day (= " + day +
				       " where Month = " + month +
				       ")");
	}

	/* Finally, decode date into internal format (ie: an integer
	 * representing the number of days since 1900-Jan-01). */
	date = day + monthOffset[month-1] + leapOffset + year*365; // Actual date calculation.

    }

    /** getDate.  Mostly used in calculating date arimthmatic.
      * @return Returns date as the number of days since 1900-Jan-01.
      */
    public int getDate() {  
      return date;
    }

    /** setDebugLevel.  Sets debugLevel variable for 1960s style debugging.
      * @deprecated Only used during code development.
      */
    public void setDebugLevel(int dLevel) {
      debugLevel = dLevel;
    }

    /** toString.  Java default string converter.
      * @return Returns date as a string that represents the number of days since 1900-Jan-01.
      */
    public String toString() {
	return Integer.toString(date);
    }

    /** between.  Calculates the number of days between two dates.  Commutative and exclusive.
      * @return Returns number of days between two dates (exclusive).
      */
    public int between(MyDate someOtherDate) {
	int between = Math.abs(date - someOtherDate.getDate())-1; // basic calculation.
	if (between < 0) // have to watch for case where the two dates are the same.
	    between = 0;
	return between;
    }

} ///:~


/* Todo
-------

1. Change date range from 0-199 to 1900-2099.

 */

PK :&)O [com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.BadDateException.html Package com.markcrocker.thoughtworks.BadDateException
All Packages  Class Hierarchy  Index

package com.markcrocker.thoughtworks.BadDateException

PK :&)vPcom/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.Dates.html Package com.markcrocker.thoughtworks.Dates
All Packages  Class Hierarchy  Index

package com.markcrocker.thoughtworks.Dates

PK :&)0Qcom/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.MyDate.html Package com.markcrocker.thoughtworks.MyDate
All Packages  Class Hierarchy  Index

package com.markcrocker.thoughtworks.MyDate

PK :&)+OUcom/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.TestMyDate.html Package com.markcrocker.thoughtworks.TestMyDate
All Packages  Class Hierarchy  Index

package com.markcrocker.thoughtworks.TestMyDate

PK /<&)׿<Jcom/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.html Package com.markcrocker.thoughtworks
All Packages  Class Hierarchy  Index

package com.markcrocker.thoughtworks

Class Index

  • Dates
  • MyDate
  • TestMyDate
  • Exception Index

  • BadDateException
  • PK ;&)Bz!Qcom/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.source.html Package com.markcrocker.thoughtworks.source
    All Packages  Class Hierarchy  Index

    package com.markcrocker.thoughtworks.source

    PK =&)=R"<"<5com/markcrocker/thoughtworks/doc/TestMyDate.java.html testmydate.java
    //: TestMyDate.java
    
    /** Tests used to verify MyDates class.
      * @author Mark Crocker <mcrocker@micron.net>
      * @author http://www.markcrocker.com/~mcrocker/
      * @version 0.92
      */
    
    package com.markcrocker.thoughtworks;
    
    public class TestMyDate {
        private int debugLevel = 0;  // vestigal 1960s style debugging tool
        
        /** testStandardDates.  Basic tests of MyDate class using several known dates,
          * comparing the number of days between and verifying the answers.
          * @return testPassed.  True if all tests were passed, false otherwise.
          */ 
        static boolean testStandardDates() {
    	boolean testPassed = true;
    	try {
    	    MyDate start1 = new MyDate(83,6,2);
    	    MyDate end1   = new MyDate(83,6,22);
    	    int daysBetween = end1.between(start1);
    	    System.out.println("Line #1:  There are " + daysBetween + " Days between 6, 2, 1983 and 6, 22, 1983.");
    	    if (daysBetween != 19) {
    		testPassed = false;
    		System.out.println("Test failed: result should have been 19 days");
    	    }
    
    	    MyDate start2 = new MyDate(84,7,4);
    	    MyDate end2   = new MyDate(84,12,25);
    	    daysBetween = end2.between(start2);
    	    System.out.println("Line #2:  There are " + daysBetween + " Days between 7, 4, 1984 and 12, 25, 1984.");
    	    if (daysBetween != 173) {
    		testPassed = false;
    		System.out.println("Test failed: result should have been 173 days");
    	    }
    
    	    MyDate start3a = new MyDate(89,1,3);
    	    MyDate end3a   = new MyDate(83,8,3);
    	    daysBetween = end3a.between(start3a);
    	    System.out.println("Line #3a: There are " + daysBetween + " Days between 1, 3, 1989 and 8, 3, 1983.");
    	    if (daysBetween != 1979) {
    		testPassed = false;
    		System.out.println("Test failed: result should have been 1979 days");
    	    }
    
    	    MyDate start3b = new MyDate(89,1,3);
    	    MyDate end3b   = new MyDate(83,3,8);
    	    daysBetween = end3b.between(start3b);
    	    System.out.println("Line #3b: There are " + daysBetween + " Days between 1, 3, 1989 and 3, 8, 1983.");
    	    if (daysBetween != 2127) {
    		testPassed = false;
    		System.out.println("Test failed: result should have been 2127 days");
    	    }
    
    	    MyDate start4 = new MyDate(100,9,3);
    	    MyDate end4   = new MyDate(100,9,5);
    	    daysBetween = end4.between(start4);
    	    System.out.println("Test #4:  There are " + daysBetween + " Days between 9, 3, 2000 and 9, 5, 2000.");
    	    if (daysBetween != 1) {
    		testPassed = false;
    		System.out.println("Test failed: result should have been 1 days");
    	    }
    
    	    MyDate start5 = new MyDate(100,9,3);
    	    MyDate end5   = new MyDate(100,9,4);
    	    daysBetween = end5.between(start5);
    	    System.out.println("Test #5:  There are " + daysBetween + " Days between 9, 3, 2000 and 9, 4, 2000.");
    	    if (daysBetween != 0) {
    		testPassed = false;
    		System.out.println("Test failed: result should have been 0 days");
    	    }
    
    	    MyDate start6 = new MyDate(100,9,3);
    	    MyDate end6   = new MyDate(100,9,3);
    	    daysBetween = end6.between(start6);
    	    System.out.println("Test #6:  There are " + daysBetween + " Days between 9, 3, 2000 and 9, 3, 2000.");
    	    if (daysBetween != 0) {
    		testPassed = false;
    		System.out.println("  Test failed: result should have been 0 days");
    	    }
    
    	    MyDate start7 = new MyDate(00,1,1);
    	    MyDate end7   = new MyDate(199,12,31);
    	    daysBetween = end7.between(start7);
    	    System.out.println("Test #7:  There are " + daysBetween + " Days between 1, 1, 1900 and 12, 31, 2099.");
    	    if (daysBetween != 73047) {
    		testPassed = false;
    		System.out.println("Test failed: result should have been 73047 days");
    	    }
    
    	} catch(BadDateException e) {      // shouldnt generate any exceptions because input is fixed.
    	    e.printStackTrace(System.err);
    	    System.exit(1);
    	}
    
    	return testPassed;
        }
    
        /** testDateExceptions.  Tests of MyDate class exceptions.  Checks
          * to make sure that known bad dates are caught by the constructor 
          * checking algorithms.  Does not verify results... yet.
          */
        static void testDateExceptions() {
    	try { MyDate badYear1 = new MyDate(-83,6,2);
    	} catch(BadDateException e) { e.printStackTrace(System.err); }
    	try { MyDate badYear2 = new MyDate(103,6,2); 		     
    	} catch(BadDateException e) { e.printStackTrace(System.err); }
    	try { MyDate badMonth1 = new MyDate(83,0,2);		     
    	} catch(BadDateException e) { e.printStackTrace(System.err); }
    	try { MyDate badMonth2 = new MyDate(83,13,2);		     
    	} catch(BadDateException e) { e.printStackTrace(System.err); }
    	try { MyDate badDay1 = new MyDate(83,6,-4);  		     
    	} catch(BadDateException e) { e.printStackTrace(System.err); }
    	try { MyDate badDay2 = new MyDate(83,6,34);  
    	} catch(BadDateException e) { e.printStackTrace(System.err); }
    	try { MyDate badDay3 = new MyDate(84,2,29);  // actually a good date, shouldnt produce an exception
    	} catch(BadDateException e) { e.printStackTrace(System.err); }
    	try { MyDate badDay3 = new MyDate(83,2,29);
    	} catch(BadDateException e) { e.printStackTrace(System.err); }
    
        }
    
        /** syntaxMessage.  Prints out syntax/help message.
          */
        private static void syntaxMessage() {
    	System.out.println("Syntax:\n" +
    			   "    TestMyDate [-t|--test|-e|--exceptions|-h|--help]\n" +
    			   " Produces test output, exception test output or this message.\n" + 
    			   " These switches may be used in combination with each other and multiple times.\n");
        }
    
    
        public static void main(String[] args) throws BadDateException {
    	int debugLevel = 0;  // vestigal 1960s style debugging tool
    
    	if (args.length < 1) {
    	    syntaxMessage();
    	} else {
    	    for (int i = 0; i < args.length; i++) {  // go through all args
    		if ( args[i].equals("-t") || 
    		     args[i].equals("--test")) {
    		    if (debugLevel > 1) { System.out.println("Test mode flag detected"); }
    		    System.out.println("Tests passed = " + testStandardDates());
    		} else if ( args[i].equals("-e") || 
    			    args[i].equals("--exceptions")) {
    		    if (debugLevel > 1) { System.out.println("Exception test mode flag detected"); }
    		    testDateExceptions();
    		} else if ( args[i].equals("-h") || 
    			    args[i].equals("--help")) {
    		    if (debugLevel > 1) { System.out.println("Help mode flag detected"); }
    		    syntaxMessage();
    		} else { // not a valid input, so spit out a syntax message.
    		    syntaxMessage();
    		    break;
    		}
    	    }
    	}
        }
    
    
    } ///:~
    
    
    /* Todo
    -------
    
    1. Add verification to exception testing routine.
    
     */
    
    
    PK /<&)  Scom/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.BadDateException.html Class com.markcrocker.thoughtworks.BadDateException
    All Packages  Class Hierarchy  This Package  Previous  Next  Index

    Class com.markcrocker.thoughtworks.BadDateException

    java.lang.Object
       |
       +----java.lang.Throwable
               |
               +----java.lang.Exception
                       |
                       +----com.markcrocker.thoughtworks.BadDateException
    

    public class BadDateException
    extends Exception

    Variable Index

     o standardMessage

    Constructor Index

     o BadDateException()
    Default exception method for BadDateException
     o BadDateException(String)
    Message version of BadDateException method

    Variables

     o standardMessage
     private static String standardMessage
    

    Constructors

     o BadDateException
     public BadDateException()
    
    Default exception method for BadDateException

     o BadDateException
     public BadDateException(String msg)
    
    Message version of BadDateException method

    Parameters:
    msg - Extra message to be provided along with the standard BadDateException message.

    All Packages  Class Hierarchy  This Package  Previous  Next  Index
    PK /<&)wHcom/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.Dates.html Class com.markcrocker.thoughtworks.Dates
    All Packages  Class Hierarchy  This Package  Previous  Next  Index

    Class com.markcrocker.thoughtworks.Dates

    java.lang.Object
       |
       +----com.markcrocker.thoughtworks.Dates
    

    public class Dates
    extends Object

    Variable Index

     o debugLevel

    Constructor Index

     o Dates()

    Method Index

     o main(String[])
     o parseDates(String[], int)
    parseDates.
     o parseFile(String)
    parseFile.
     o syntaxMessage()
    syntaxMessage.

    Variables

     o debugLevel
     private int debugLevel
    

    Constructors

     o Dates
     public Dates()
    

    Methods

     o parseDates
     private static MyDate parseDates(String args[],
                                      int i) throws BadDateException
    
    parseDates. Converts an array of strings into a MyDate object. Input format is VERY fussy. Expects

    Parameters:
    args - is a string array of at least three elements. The elements starting at the indicated index should be MM, DD, YYYY[,] respectively.
    i - is the array index where the strings defining the date start.
    Returns:
    Initialized MyDate object.
    Throws: BadDateException
    via MyDate constructor.
     o parseFile
     private static void parseFile(String fileName) throws FileNotFoundException, IOException, BadDateException
    
    parseFile. Converts a file with pairs of dates on each line into dates and prints out the number of days between the two dates. The date format is VERY fussy. Each date should be in the format MM, DD, YYYY[,].

    Parameters:
    fileName - is the file that data data is to be read from.
    Throws: BadDateException
    via MyDate constructors
     o syntaxMessage
     private static void syntaxMessage()
    
    syntaxMessage. Prints out syntax/help message.

     o main
     public static void main(String args[]) throws FileNotFoundException, IOException, BadDateException
    

    All Packages  Class Hierarchy  This Package  Previous  Next  Index
    PK /<&)?Icom/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.MyDate.html Class com.markcrocker.thoughtworks.MyDate
    All Packages  Class Hierarchy  This Package  Previous  Next  Index

    Class com.markcrocker.thoughtworks.MyDate

    java.lang.Object
       |
       +----com.markcrocker.thoughtworks.MyDate
    

    public class MyDate
    extends Object

    Variable Index

     o date
     o debugLevel
     o leapMonth
     o leapOffset
     o monthLength
     o monthOffset

    Constructor Index

     o MyDate(int, int, int)
    MyDate primary constructor.

    Method Index

     o between(MyDate)
    between.
     o getDate()
    getDate.
     o setDebugLevel(int)
    setDebugLevel. Deprecated.
     o toString()
    toString.

    Variables

     o monthLength
     private static int monthLength[]
    
     o monthOffset
     private static int monthOffset[]
    
     o leapMonth
     private int leapMonth
    
     o leapOffset
     private int leapOffset
    
     o debugLevel
     private int debugLevel
    
     o date
     private int date
    

    Constructors

     o MyDate
     MyDate(int year,
            int month,
            int day) throws BadDateException
    
    MyDate primary constructor. Converts date to an internal format for storage and checks for invalid or out of range dates.

    Parameters:
    year - year past 1900 (0-199). Ex: 1981 will be year 81, 2009 is 109.
    month - month of the year (1-12).
    day - day of the month (1-28,29,30, or 31) depending on the month.
    Throws: BadDateException
    thrown if the date is malformed or out of range.

    Methods

     o getDate
     public int getDate()
    
    getDate. Mostly used in calculating date arimthmatic.

    Returns:
    Returns date as the number of days since 1900-Jan-01.
     o setDebugLevel
     public void setDebugLevel(int dLevel)
    
    Note: setDebugLevel() is deprecated. Only used during code development.

    setDebugLevel. Sets debugLevel variable for 1960s style debugging.

     o toString
     public String toString()
    
    toString. Java default string converter.

    Returns:
    Returns date as a string that represents the number of days since 1900-Jan-01.
    Overrides:
    toString in class Object
     o between
     public int between(MyDate someOtherDate)
    
    between. Calculates the number of days between two dates. Commutative and exclusive.

    Returns:
    Returns number of days between two dates (exclusive).

    All Packages  Class Hierarchy  This Package  Previous  Next  Index
    PK /<&)YMcom/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.TestMyDate.html Class com.markcrocker.thoughtworks.TestMyDate
    All Packages  Class Hierarchy  This Package  Previous  Next  Index

    Class com.markcrocker.thoughtworks.TestMyDate

    java.lang.Object
       |
       +----com.markcrocker.thoughtworks.TestMyDate
    

    public class TestMyDate
    extends Object

    Variable Index

     o debugLevel

    Constructor Index

     o TestMyDate()

    Method Index

     o main(String[])
     o syntaxMessage()
    syntaxMessage.
     o testDateExceptions()
    testDateExceptions.
     o testStandardDates()
    testStandardDates.

    Variables

     o debugLevel
     private int debugLevel
    

    Constructors

     o TestMyDate
     public TestMyDate()
    

    Methods

     o testStandardDates
     static boolean testStandardDates()
    
    testStandardDates. Basic tests of MyDate class using several known dates, comparing the number of days between and verifying the answers.

    Returns:
    testPassed. True if all tests were passed, false otherwise.
     o testDateExceptions
     static void testDateExceptions()
    
    testDateExceptions. Tests of MyDate class exceptions. Checks to make sure that known bad dates are caught by the constructor checking algorithms. Does not verify results... yet.

     o syntaxMessage
     private static void syntaxMessage()
    
    syntaxMessage. Prints out syntax/help message.

     o main
     public static void main(String args[]) throws BadDateException
    

    All Packages  Class Hierarchy  This Package  Previous  Next  Index
    PK \=&)Ju+--.com/markcrocker/thoughtworks/doc/dates.pl.html dates.pl
    extproc perl -S  
    
    # Rough perl program to calculate days between dates
    
    use HTTP::Date qw(str2time);
    
    $secondsADay = 60*60*24;
    
    $days= abs(str2time($ARGV[1])- str2time($ARGV[0]))/$secondsADay-1;
    
    print "$days Days\n";
    
    
    exit;
    
    # extproc is an OS/2 trick to get the .pl to execute.
    # in UNIX, you need a line like #!/usr/bin/perl...
    
    PK Q&)=+com/markcrocker/thoughtworks/doc/index.html ThoughtWorks Coding Test: Dates

    ThoughtWorks Coding Test: Dates

    Documentation:

    This project consistes of a Java program that is intended to solve the problem of calculating the number of days between two supplied dates that was posed as problem #1 in the ThoughtWorks coding test. The primary entry class is the Dates wrapper class. All intended uses of this program can be accessed via the Dates class. The working code is in the MyDate class and the BadDateException class. Test code resides in the TestMyDate class.

    Quick Start:

    The quickest way to get started is to follow these steps:

    1. Type the following at the command prompt:
      java -classpath %classpath%com.markcrocker.thoughtworks.jar com.markcrocker.thoughtworks.Dates -h
    2. Follow the syntax recommended by the last step to make the program do what you want to do.

    This has some disadvantages, such as not having access to the source code and documentation that is included in the jar file. A more reasonable way to get started is:

    1. Unjar com.markcrocker.thoughtworks.jar.
    2. Type the following at the command prompt:
      java com.markcrocker.thoughtworks.Dates -h
    3. Follow the syntax recommended by the last step to make the program do what you want to do.

    Both cases assumes that your java executable is java. Some operating systems require the use of jre or some other executable to start java programs. See your system documentation for details.

    Similarly %classpath% would be $classpath; in UNIX or something else in other operating systems. Again, see the documentation for your particular OS.

    The unjar operation can usually be accomplished with unjar com.markcrocker.thoughtworks or jar xvf com.markcrocker.thoughtworks depending on your OS.

    General:

    Thare are a few points that are worth noting. There is a sample input file included with the distribution. To use it, type something like:

    java com.markcrocker.thoughtworks.Dates -f com/markcrocker/thoughtworks/testFile.txt

    Command line forms can be used multiple times. For example something like:
    java com.markcrocker.thoughtworks.Dates -h 6, 2, 1983 6, 22, 1983 -t 7, 4, 1984, 12, 25, 1984 1, 3, 1989, 8, 3, 1983
    is a perfectly acceptable input. Note that between the second last pair of dates and the last pair of dates, there is no comma after the year "1984". This is optional. The command line input parsing method works with or without a comma after the year. All other commas are required. Spaces between tokens are required as well. Additional spaces are optional. Multiple switches are allowed, but they each require a separate space and "-". So -h -t -e works fine, but the UNIX style -hte does not work.

    Source Code:

    The HTML "fontified" source code is available from:

    The raw java source code can be found in the source subdirectory.

    JavaDocs:

    The top level of the javadocs for this package is available from packages.html.

    Project Status:

    I do not consider this project entirely finished. However, I have released the project for the following reasons:

    1. The project meets the requirements.
    2. On-time delivery is more important than adding fancy features or code elegance.

    There were LOTS of other features that I wanted to add to this project. I generally try to avoid the tempation to fall in to the trap of "creaping elegance", but this was a test that was supposed to illustrate my programming abilities and I got very litte response from my customers regarding feature requirements beyond what was in the original requirements. Consequently, I did add a number of features, such as syntax message, multiple input methods and parsing that allows multiple data sets on one line. Other features that I was working on can be seen in the "todo" comments at the bottom of the source code files (eg: Dates todos). If you are interested in seeing any of these extras added to the package, please let me know. I would love the excuse to do some of these.

    Motivation:

    Since this is a test and there were three options, you might be wondering why I chose to do the Dates problem especially when it seems to be the easiest question of the three. Normally, I would've picked the most difficult of the group to demonstrate my abilities as thoroughly as possible. However, the Dates problem peaked my interest because I've encountered a number of tricky date related issues in my past Perl programming experience (see Dates.pl example) and wanted to explore the Java solutions to these problems. Also, my earlier forray into Java's Date class indicated that most of the Date class is now deprecated and I wanted to explore its' replacement, the Calendar class. Naturally, the requirements of the test prohibitted the use of the Date or Calendar classes, but I did use this as an excuse to learn more about them. None of the code I developed during that learning process is included in this release of this project.


    Mark Crocker's home page is available at: http://www.markcrocker.com/~mcrocker
    This page last updated 2000-Sep-01 08:34 MDT (Friday) by Mark Crocker
    Comments or Suggestions? email: mcrocker@micron.net
    Copyright© 2000, Mark Crocker All rights reserved.

    PK .<&)O9Eii.com/markcrocker/thoughtworks/doc/packages.html Package Index
    API User's Guide  Class Hierarchy  Index

    Package Index

    Other Packages

  • package com.markcrocker.thoughtworks
  • PK /<&)ic&&*com/markcrocker/thoughtworks/doc/tree.html Class Hierarchy
    All Packages  Index

    Class Hierarchy

    • class java.lang.Object
      • class com.markcrocker.thoughtworks.Dates
      • class com.markcrocker.thoughtworks.MyDate
      • class com.markcrocker.thoughtworks.TestMyDate
      • class java.lang.Throwable (implements java.io.Serializable)
    PK qS&)META-INF/MANIFEST.MFPK !<&)3com/markcrocker/thoughtworks/BadDateException.classPK !<&))$/(Ucom/markcrocker/thoughtworks/Dates.classPK !<&)i9)A'com/markcrocker/thoughtworks/MyDate.classPK "<&),QQ-/com/markcrocker/thoughtworks/TestMyDate.classPK ]S&)w)!@com/markcrocker/thoughtworks/testFile.txtPK k#) 1cc*@com/markcrocker/thoughtworks/testfile.txt~PK 9&)9Acom/markcrocker/thoughtworks/source/BadDateException.javaPK 9&)[.Ecom/markcrocker/thoughtworks/source/Dates.javaPK ;&)T/e`com/markcrocker/thoughtworks/source/MyDate.javaPK >&)363rcom/markcrocker/thoughtworks/source/TestMyDate.javaPK /<&)@!!.̌com/markcrocker/thoughtworks/doc/AllNames.htmlPK =&)T:#5 5 ;com/markcrocker/thoughtworks/doc/BadDateException.java.htmlPK I&)/d770com/markcrocker/thoughtworks/doc/Dates.java.htmlPK k6&)`^^)com/markcrocker/thoughtworks/doc/Dates.plPK =&)C[p&&1Ecom/markcrocker/thoughtworks/doc/MyDate.java.htmlPK :&)O [com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.BadDateException.htmlPK :&)vPcom/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.Dates.htmlPK :&)0Q& com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.MyDate.htmlPK :&)+OUe"com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.TestMyDate.htmlPK /<&)׿<J$com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.htmlPK ;&)Bz!Q)com/markcrocker/thoughtworks/doc/Package-com.markcrocker.thoughtworks.source.htmlPK =&)=R"<"<5?+com/markcrocker/thoughtworks/doc/TestMyDate.java.htmlPK /<&)  Sgcom/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.BadDateException.htmlPK /<&)wHtcom/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.Dates.htmlPK /<&)?Icom/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.MyDate.htmlPK /<&)YMucom/markcrocker/thoughtworks/doc/com.markcrocker.thoughtworks.TestMyDate.htmlPK \=&)Ju+--.com/markcrocker/thoughtworks/doc/dates.pl.htmlPK Q&)=+7com/markcrocker/thoughtworks/doc/index.htmlPK .<&)O9Eii.com/markcrocker/thoughtworks/doc/packages.htmlPK /<&)ic&&*Ccom/markcrocker/thoughtworks/doc/tree.htmlPKi