Skip to content

Commit

Permalink
New utility methods for Date and removed workflows (#9)
Browse files Browse the repository at this point in the history
* Added new utility methods in DateUtils

* Added new utility methods for DateUtils

* Deleted CodeQL and Maven Publish workflows
  • Loading branch information
shortthirdman authored Jun 17, 2024
1 parent ee08c56 commit 349fc01
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 130 deletions.
91 changes: 0 additions & 91 deletions .github/workflows/codeql.yml

This file was deleted.

34 changes: 0 additions & 34 deletions .github/workflows/maven-publish.yml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.shortthirdman.primekit.essentials.common;

import java.text.MessageFormat;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.chrono.Chronology;
import java.time.chrono.IsoChronology;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.util.Objects;


public record YearWeek(int year, int week) {

public static YearWeek from(TemporalAccessor temporal) {
Objects.requireNonNull(temporal, "temporal");
try {
if (!IsoChronology.INSTANCE.equals(Chronology.from(temporal))) {
temporal = LocalDate.from(temporal);
}
return new YearWeek(temporal.get(ChronoField.YEAR), temporal.get(ChronoField.ALIGNED_WEEK_OF_YEAR));
} catch (DateTimeException ex) {
String mf = MessageFormat.format("Unable to obtain YearWeek from TemporalAccessor: {0} of type {1}", temporal, temporal.getClass().getName());
throw new DateTimeException(mf, ex);
}
}

@Override
public String toString() {
return MessageFormat.format("{0}-{1}", year, week);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.shortthirdman.primekit.essentials.common.util;

import com.shortthirdman.primekit.essentials.common.YearWeek;
import org.apache.commons.lang3.StringUtils;

import java.sql.Timestamp;
Expand All @@ -11,6 +12,7 @@
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.IsoFields;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
Expand All @@ -21,7 +23,6 @@
* @apiNote Utility class for operations on {@link LocalDate}, {@link Date}, {@link LocalDateTime}
* @author shortthirdman
* @since 1.0
* https://howtodoinjava.com/java/date-time/date-validation/
*/
public final class DateUtils {

Expand Down Expand Up @@ -392,4 +393,153 @@ public static String monthShortNameToFullName(String abbreviation) {
return monthOptional.orElseThrow(IllegalArgumentException::new)
.getDisplayName(TextStyle.FULL, Locale.getDefault());
}

/**
* Get the number of quarters in between two dates
* @param start the start date
* @param end the end date
* @return the number of quarters
*/
public static Long quarterCount(LocalDate start, LocalDate end) {
if (start == null || end == null) {
throw new IllegalArgumentException("Start date or end date can not be null");
}

return IsoFields.QUARTER_YEARS.between(start, end);
}

/**
* Get the quarter number in a short pattern-style
* @param date the {@link LocalDate}
* @return the quarter in the format "Q{1-4}"
*/
public static String shortQuarterNumber(LocalDate date) {
if (date == null) {
throw new IllegalArgumentException("Date can not be null");
}

return date.format(DateTimeFormatter.ofPattern("QQQ", Locale.ENGLISH));
}

/**
* Get the quarter number in a long pattern-style
* @param date the {@link LocalDate}
* @return the quarter in the format "n-th quarter"
*/
public static String longQuarterNumber(LocalDate date) {
if (date == null) {
throw new IllegalArgumentException("Date can not be null");
}

return date.format(DateTimeFormatter.ofPattern("QQQQ", Locale.ENGLISH));
}

/**
* Get quarter number for a given date
* @param date the {@link LocalDate}
* @return quarter number
*/
public static Integer getQuarterNumber(LocalDate date) {
if (date == null) {
throw new IllegalArgumentException("Date can not be null");
}

return date.get(IsoFields.QUARTER_OF_YEAR);
}

/**
* Split date-time range into equal intervals
* @param start the start date
* @param end the end date
* @param n the intervals
* @return list of date-time
*/
public static List<LocalDateTime> splitDateTimeRange(LocalDateTime start, LocalDateTime end, int n) {
if (start == null || end == null) {
throw new IllegalArgumentException("Start date or end date can not be null");
}

Duration range = Duration.between(start, end);
Duration interval = range.dividedBy(n - 1);
List<LocalDateTime> listOfDates = new ArrayList<>();
LocalDateTime timeline = start;
for (int i = 0; i < n - 1; i++) {
listOfDates.add(timeline);
timeline = timeline.plus(interval);
}
listOfDates.add(end);
return listOfDates;
}

/**
* Split date-time range into days
* @param start the start date
* @param end the end date
* @return list of date
*/
public static List<LocalDate> splitDateRangeIntoDays(LocalDate start, LocalDate end) {
if (start == null || end == null) {
throw new IllegalArgumentException("Start date or end date can not be null");
}

long numOfDaysBetween = ChronoUnit.DAYS.between(start, end);
return IntStream.iterate(0, i -> i + 1)
.limit(numOfDaysBetween)
.mapToObj(start::plusDays)
.collect(Collectors.toList());
}

/**
* Split date-time range into months
* @param start the start date
* @param end the end date
* @return list of year-month
*/
public static List<YearMonth> splitDateRangeIntoMonths(LocalDate start, LocalDate end) {
if (start == null || end == null) {
throw new IllegalArgumentException("Start date or end date can not be null");
}

long numOfDaysBetween = ChronoUnit.MONTHS.between(start, end);
return IntStream.iterate(0, i -> i + 1)
.limit(numOfDaysBetween)
.mapToObj(i -> YearMonth.from(start.plusMonths(i)))
.collect(Collectors.toList());
}

/**
* Split date-time range into years
* @param start the start date
* @param end the end date
* @return the list of years
*/
public static List<Year> splitDateRangeIntoYears(LocalDate start, LocalDate end) {
if (start == null || end == null) {
throw new IllegalArgumentException("Start date or end date can not be null");
}

long numOfDaysBetween = ChronoUnit.YEARS.between(start, end);
return IntStream.iterate(0, i -> i + 1)
.limit(numOfDaysBetween)
.mapToObj(i -> Year.from(start.plusYears(i)))
.collect(Collectors.toList());
}

/**
* Split date-time range into weeks
* @param start the start date
* @param end the end date
* @return the list of year-week
*/
public static List<YearWeek> splitDateRangeIntoWeeks(LocalDate start, LocalDate end) {
if (start == null || end == null) {
throw new IllegalArgumentException("Start date or end date can not be null");
}

long numOfDaysBetween = ChronoUnit.WEEKS.between(start, end);
return IntStream.iterate(0, i -> i + 1)
.limit(numOfDaysBetween)
.mapToObj(i -> YearWeek.from(start.plusWeeks(i)))
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
import org.junit.jupiter.api.Test;

import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
Expand Down Expand Up @@ -198,4 +195,29 @@ public void givenMonthShortName_convertFullName() {
assertEquals("January", DateUtils.monthShortNameToFullName("Jan"));
assertThrows(IllegalArgumentException.class, () -> DateUtils.monthShortNameToFullName("Fut"));
}

@Test
public void givenLocalDate_getQuarter() {
LocalDate date = LocalDate.of(2024, Month.FEBRUARY, 19);
assertEquals(1, DateUtils.getQuarterNumber(date));
assertThrows(IllegalArgumentException.class, () -> DateUtils.getQuarterNumber(null));
}

@Test
public void givenLocalDate_getFormattedQuarter() {
LocalDate date = LocalDate.of(2024, Month.FEBRUARY, 19);
assertEquals("Q1", DateUtils.shortQuarterNumber(date));
assertEquals("1st quarter", DateUtils.longQuarterNumber(date));
assertThrows(IllegalArgumentException.class, () -> DateUtils.shortQuarterNumber(null));
assertThrows(IllegalArgumentException.class, () -> DateUtils.longQuarterNumber(null));
}

@Test
public void givenStartDate_givenEndDate_getQuarterCount() {
LocalDate start = LocalDate.of(2024, Month.FEBRUARY, 19);
LocalDate end = LocalDate.of(2024, Month.MAY, 5);
assertEquals(1, DateUtils.quarterCount(start, end));
assertThrows(IllegalArgumentException.class, () -> DateUtils.quarterCount(null, end));
assertThrows(IllegalArgumentException.class, () -> DateUtils.quarterCount(start, null));
}
}

0 comments on commit 349fc01

Please sign in to comment.