Date value objects

 


Date and time headaches

Storing dates and/or time is something that we often require to do. Sadly because of many country specific rules it is often more complex then people think. In a Rest API you also need to have a good agreement how to parse/encode dates as JSON/XML have no default format for dates. For that reason one of the first libraries I made was a date value objects library.

It contains basically a few common value object related to date or time and works with a trait to make it possible to make your own date and time classes yourself.

Already defined value objects

  • DateWithTimezone: This is basically the same as DateTime where it contains date, time and timezone. It will throw an error if an invalid date is provided, for example 30 february.
  • HoursAndMinutes: Just a timestamp with hours and minutes, for example "10:00"
  • LocalDate: Just represents a date in format: 'YYYY-MM-DD" with no timezone information.
  • Time: Just a time with hours, minutes and seconds, for example: "10:00:23"
  • UnixTimestamp: Represent a Unix timestamp

Creating your own value objects

To make your own date value object all you need is adding a specific date trait and provide the implementation of 2 methods: one for the date time format you use and the other one if you are strict about invalid dates or not.
use Apie\Core\ValueObjects\Interfaces\TimeRelatedValueObjectInterface;
use Apie\DateValueObjects\Concerns\IsDateValueObject;

class DutchDate implements TimeRelatedValueObjectInterface
{
  use IsDateValueObject;
  public static function getDateFormat(): string
  {
    return 'd-m-Y';
  }

  protected function isStrictFormat(): bool
  {
    return false;
  }
}
That is all you need! This class only accepts dates formatted in the Dutch format (so days before months).
So what is the 'strict' format? Basically it does 2 things. If a value object is not strict it will accept non-existent dates like 30 february, but it will also enforce you have to prefix your days and months with '0' if it is lower than 10. The way how the trait works I could not separate these.

To make it a little bit more useful, this package also comes with a list of interfaces and traits to tell it handles dates, time, etc. If we add this, this becomes our DutchDate value object.

use Apie\Core\ValueObjects\Interfaces\TimeRelatedValueObjectInterface;
use Apie\DateValueObjects\Concerns\CanCreateInstanceFromDateTimeObject;
use Apie\DateValueObjects\Concerns\CanHaveDayIntervals;
use Apie\DateValueObjects\Concerns\CanHaveMonthIntervals;
use Apie\DateValueObjects\Concerns\CanHaveYearIntervals;
use Apie\DateValueObjects\Concerns\IsDateValueObject;
use Apie\DateValueObjects\Interfaces\WorksWithDays;
use Apie\DateValueObjects\Interfaces\WorksWithMonths;
use Apie\DateValueObjects\Interfaces\WorksWithYears;

class DutchDate implements WorksWithDays, WorksWithMonths, WorksWithYears
{
  use CanCreateInstanceFromDateTimeObject;
  use IsDateValueObject;
  use CanHaveDayIntervals;
  use CanHaveMonthIntervals;
  use CanHaveYearIntervals;
  public static function getDateFormat(): string
  {
    return 'd-m-Y';
  }

  protected function isStrictFormat(): bool
  {
    return false;
  }
}
Now we have a DutchDate value object with helper methods.
$instance = DutchDate::createFromCurrentTime();
$twoMonthsLater = $instance->nextMonth()->nextMonth();
  
What's really cool is that internally it still remembers the original day that was entered, so if I say $instance->nextMonth()->nextMonth() on 31 january 2019, it will become 31 march 2019. There are many bugs where this value becomes 28 march, 29 march or 3 april 2019.

Conclusion

So what are the benefits over this library over the regular DateTime objects?
  • Pre-defined behaviour what dates are parsed.
  • Can be used to indicate whether a field only data is a date or a time or both.
  • Can be used to modify dates with good edge cases handling, like remembering the original day of the original object when asking for the next month.
  • It is very easy to make your own value objects and use these in your own application.
  • It has support for apie/faker so we can fake proper faker data by providing only dates and times in this format provided.

Links

Comments