ecraig12345
ecraig12345

Reputation: 2457

Represent date (without time) as single integer

Is there a standard way to represent a date as a single integer? (I only need to store dates, not full timestamps.)

If it matters, the reason I want to do this is because I'm storing the dates in a SQLite database on Android and would like to store them as numbers so they can be compared/sorted efficiently to return results from queries.

Upvotes: 3

Views: 4051

Answers (3)

Keith Thompson
Keith Thompson

Reputation: 263577

One good option might be YYYYMMDD, for example encoding today (Jan 13, 2014) as the integer 20140113.

Advantages:

  • It works for comparisons, as long as you only care about <, ==, and >;
  • It's reasonably human-readable;
  • It's compatible with the ISO 8601 standard.

Disadvantages:

  • It's not as easy to compute differences between dates;
  • SQLite won't recognize it as a date.

On the last point: The SQLite3 documentation says that SQLite3 has no specific storage types for dates and/or times. Instead, it recommends using one of:

  • TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
  • REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
  • INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.

all of which apparently can be processed using SQLite's built-in date and time functions.

The latter argues in favor of the solution in bdf's answer. Picking an arbitrary time within the specified day is admittedly problematic, but I suggest picking noon UTC is unlikely to cause too many problems as long as you're careful to use it consistently. (Noon UTC can be on a different day if your time zone offset is 12 hours or more, but that's not an issue for most of the world.)

Upvotes: 4

Holtwick
Holtwick

Reputation: 1966

An important detail to keep in mind are time zones. If e.g. your time falls in the gap between your time zone offset and GMT you might get unexpected results. So at first I propose we discuss date as the one visible to the user which is usually the one of the local time zone.

So if we assume local time, and we want to make use of the Date objects, there are 2 possible solutions, which I will present as JavaScript unit test style. First one is the one presented by Keith Thompson previously:

let date = new Date('1987-12-31T01:02:03')

let simpleDateInteger = (
  date.getFullYear() * 10000 +
  (date.getMonth() + 1) * 100 +
  date.getDate()
)

expect(simpleDateInteger).toBe(19871231)

let fromSimpleDateInteger = new Date(
  simpleDateInteger / 10000, // year
  simpleDateInteger / 100 % 100 - 1, // month
  simpleDateInteger % 100 // day
)

expect(fromSimpleDateInteger.toDateString()).toEqual(date.toDateString())

If you need more compact integers and each integer +1 representing the next day, i.e. a continuous representation you can go with this one:

let date = new Date('1987-12-31T00:01:02')

const DAY_IN_MILLISECONDS = 86400 * 1000

let timeZoneInMilliSeconds = date.getTimezoneOffset() * 60 * 1000

let continuousDateInteger = Math.floor(
  (date.getTime() - timeZoneInMilliSeconds) / DAY_IN_MILLISECONDS
)

expect(continuousDateInteger).toBe(6573)

let fromContinuousDateInteger = new Date(
  continuousDateInteger * DAY_IN_MILLISECONDS + timeZoneInMilliSeconds
)

expect(fromContinuousDateInteger.toDateString()).toEqual(date.toDateString())

Upvotes: 0

bdf
bdf

Reputation: 247

just set the time for every day to an arbitrary time of your choosing, such as 2 am.

Storing them as timestamps anyway might still be a good idea, since you'd have a lot more date formatting options.

Upvotes: 2

Related Questions