Java tutorial
/* * NorthRidge Software, LLC - Copyright (c) 2019. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.nridge.core.base.std; import com.nridge.core.base.field.Field; import org.apache.commons.lang3.StringUtils; import java.text.ParseException; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.time.DayOfWeek; import java.time.LocalDate; import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.util.*; /** * The DatUtl class provides static convenience methods for calculating date/time * conversions. * <p> * The Apache Commons has a number of good utility methods for date/time calculations. * http://commons.apache.org/lang/api-2.5/org/apache/commons/lang/time/DateUtils.html * </p> * * @author Al Cole * @version 1.0 Nov 27, 2014 * @since 1.0 */ public class DatUtl { // http://www.coderanch.com/t/410264/java/java/Julian-Gregorian-date-conversion // http://users.zoominternet.net/~matto/Java/Julian%20Date%20Converter.htm // Gregorian Calendar adopted Oct. 15, 1582 (2299161) public static double HALFSECOND = 0.5; public static List<SimpleDateFormat> mDateFormatList = null; public static int GREGORIANSTARTDATE = 15 + 31 * (10 + 12 * 1582); private DatUtl() { } /** * Returns the Julian day number that begins at noon of this day. * Positive year signifies A.D., negative year B.C. * Remember that the year after 1 B.C. was 1 A.D. * <code> * System.out.println("Julian date for May 23, 1968 : " + toJulian(new int[]{1968, 5, 23})); * </code> * <p> * Reference: Numerical Recipes in C, 2nd ed., Cambridge University Press 1992 * </p> * @param aYmd Three value integer array (Year, Month, Day). * @return The calculated Julian Day value. */ public static double toJulian(int[] aYmd) { int year = aYmd[0]; int month = aYmd[1]; // jan=1, feb=2, ... int day = aYmd[2]; int julianYear = year; if (year < 0) julianYear++; int julianMonth = month; if (month > 2) { julianMonth++; } else { julianYear--; julianMonth += 13; } double julian = (java.lang.Math.floor(365.25 * julianYear) + java.lang.Math.floor(30.6001 * julianMonth) + day + 1720995.0); if (day + 31 * (month + 12 * year) >= GREGORIANSTARTDATE) { // change over to Gregorian calendar int ja = (int) (0.01 * julianYear); julian += 2 - ja + (0.25 * ja); } return java.lang.Math.floor(julian); } /** * Returns the Julian day number that begins at noon of this day. * Positive year signifies A.D., negative year B.C. * Remember that the year after 1 B.C. was 1 A.D. * <code> * System.out.println("Julian date for May 23, 1968 : " + toJulian(new Date())); * </code> * <p> * Reference: Numerical Recipes in C, 2nd ed., Cambridge University Press 1992 * </p> * @param aDate The date to convert. * @return The calculated Julian Day value. */ public static double toJulian(Date aDate) { int[] yearMonthDay = new int[3]; TimeZone timeZone = TimeZone.getDefault(); Calendar calendarInstance = Calendar.getInstance(timeZone); calendarInstance.setTime(aDate); yearMonthDay[0] = calendarInstance.get(Calendar.YEAR); yearMonthDay[1] = calendarInstance.get(Calendar.MONTH) + 1; yearMonthDay[2] = calendarInstance.get(Calendar.DAY_OF_MONTH); return toJulian(yearMonthDay); } /** * Converts a Julian day to a calendar date. * <p> * Reference: Numerical Recipes in C, 2nd ed., Cambridge University Press 1992 * </p> * @param aJulianDay a Julian Day value. * @return A three value integer array {Y, M, D} */ public static int[] fromJulian(double aJulianDay) { int jalpha, ja, jb, jc, jd, je, year, month, day; ja = (int) aJulianDay; if (ja >= GREGORIANSTARTDATE) { jalpha = (int) (((ja - 1867216) - 0.25) / 36524.25); ja = ja + 1 + jalpha - jalpha / 4; } jb = ja + 1524; jc = (int) (6680.0 + ((jb - 2439870) - 122.1) / 365.25); jd = 365 * jc + jc / 4; je = (int) ((jb - jd) / 30.6001); day = jb - jd - (int) (30.6001 * je); month = je - 1; if (month > 12) month = month - 12; year = jc - 4715; if (month > 2) year--; if (year <= 0) year--; return new int[] { year, month, day }; } /** * Attempts to detect the date/time format of the value and create * a 'Date' object. * * @param aDateTimeValue String value. * @return Date object if the format is recognized or <i>null</i>. */ public static Date detectCreateDate(String aDateTimeValue) { Date createDate = null; if (StringUtils.isNotEmpty(aDateTimeValue)) { if (mDateFormatList == null) { mDateFormatList = new ArrayList<SimpleDateFormat>(); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_ISO8601DATETIME_DEFAULT)); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_ISO8601DATETIME_MILLI2D)); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_ISO8601DATETIME_MILLI3D)); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_RFC1123_DATE_TIME)); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_SQLORACLEDATE_DEFAULT)); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_SQLISODATE_DEFAULT)); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_SQLISOTIME_DEFAULT)); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_SQLISODATETIME_DEFAULT)); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_DATE_DEFAULT)); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_TIME_AMPM)); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_TIME_PLAIN)); mDateFormatList.add(new SimpleDateFormat(Field.FORMAT_TIMESTAMP_PACKED)); } ParsePosition parsePosition = new ParsePosition(0); for (SimpleDateFormat sdf : mDateFormatList) { sdf.setLenient(false); createDate = sdf.parse(aDateTimeValue, parsePosition); if (createDate != null) break; } } return createDate; } /** * Calculates the number of business days (excluding weekends) * between two dates (inclusive). * <p> * https://stackoverflow.com/questions/4600034/calculate-number-of-weekdays-between-two-dates-in-java * </p> * @param aStartDate Start date. * @param anEndDate End date. * * @return Number of business days. */ @SuppressWarnings("UnnecessaryLocalVariable") public static long calculateBusinessDays(LocalDate aStartDate, LocalDate anEndDate) { DayOfWeek startWeekDay = aStartDate.getDayOfWeek().getValue() < 6 ? aStartDate.getDayOfWeek() : DayOfWeek.MONDAY; DayOfWeek endWeekDay = anEndDate.getDayOfWeek().getValue() < 6 ? anEndDate.getDayOfWeek() : DayOfWeek.FRIDAY; long numberOfWeeks = ChronoUnit.DAYS.between(aStartDate, anEndDate) / 7; long totalWeekDays = numberOfWeeks * 5 + Math.floorMod(endWeekDay.getValue() - startWeekDay.getValue(), 5); return totalWeekDays + 1; } /** * Calculates the number of business days (excluding weekends) * between two dates (inclusive). In addition, this utility * method will factor in holidays (e.g. skip them in the count) * for the calculation. * <p> * https://stackoverflow.com/questions/4600034/calculate-number-of-weekdays-between-two-dates-in-java * </p> * * @param aStartDate Start date. * @param anEndDate End date. * @param aHolidayList List of holidays to skip. * * @return Number of business days. */ public static long calculateBusinessDays(LocalDate aStartDate, LocalDate anEndDate, List<LocalDate> aHolidayList) { long totalBusinessDays = calculateBusinessDays(aStartDate, anEndDate); if ((totalBusinessDays > 0) && (aHolidayList != null)) { for (LocalDate holidayDate : aHolidayList) { if (holidayDate.isEqual(aStartDate)) totalBusinessDays--; else if (holidayDate.isEqual(anEndDate)) totalBusinessDays--; else if ((holidayDate.isAfter(aStartDate)) && (holidayDate.isBefore(anEndDate))) totalBusinessDays--; } } return Math.max(totalBusinessDays, 0); } }