19

I can't see any info about that. Where can I find the oldest date Mysql can support ?

user310291
  • 36,946
  • 82
  • 271
  • 487

7 Answers7

38

For the specific example you used on your question (year 1200), technically things will work.

In general, however, timestamps are unadvisable for this uses. First, the range limitation is arbitrary: in MySQL it's Jan 1st, 1000. If you are working with 12-13th century stuff, things go fine... but if at some moment you need to add something older (10th century or earlier), the date will miserably break, and fixing the issue will require re-formatting all your historic dates into something more adequate.

Timestamps are normally represented as raw integers, with a given "tick interval" and "epoch point", so the number is indeed the number of ticks elapsed since the epoch to the represented date (or viceversa for negative dates). This means that, as with any fixed-with integer data-type, the set of representable values is finite. Most timestamp formats I know about sacrifice range in favor of precision, mostly because applications that need to perform time arithmetic often need to do so with a decent precision; while applications that need to work with historical dates very rarely need to perform serious arithmetic.

In other words, timestamps are meant for precise representation of dates. Second (or even fraction of second) precission makes no sense for historical dates: could you tell me, down to the milliseconds, when was Henry the 8th crowned as King of England?

In the case of MySQL, the format is inherently defined as "4-digit years", so any related optimization can rely on the assumption that the year will have 4 digits, or that the entire string will have exactly 10 chars ("yyyy-mm-dd"), etc. It's just a matter of luck that the date you mentioned on your title still fits, but even relying on that is still dangerous: besides what the DB itself can store, you need to be aware of what the rest of your server stack can manipulate. For example, if you are using PHP to interact with your database, trying to handle historical dates is very likely to crash at some point or another (on a 32-bit environment, the range for UNIX-style timestamps is December 13, 1901 through January 19, 2038).

In summary: MySQL will store properly any date with a 4-digit year; but in general using timestamps for historical dates is almost guaranteed to trigger issues and headaches more often than not. I strongly advise against such usage.

Hope this helps.


Edit/addition:

Thank you for this very insteresting answer. Should I create my own algo for historical date or choose another db but which one ? – user284523

I don't think any DB has too much support for this kind of dates: applications using it most often have enough with string-/text- representation. Actually, for dates on year 1 and later, a textual representation will even yield correct sorting / comparisons (as long as the date is represented by order of magnitude: y,m,d order). Comparisons will break, however, if "negative" dates are also involved (they would still compare as earlier than any positive one, but comparing two negative dates would yield a reversed result).

If you only need Year 1 and later dates, or if you don't need sorting, then you can make your life a lot easier by using strings.

Otherwise, the best approach is to use some kind of number, and define your own "tick interval" and "epoch point". A good interval could be days (unless you really need further precission, but even then you can rely on "real" (floating-point) numbers instead of integers); and a reasonable epoch could be Jan 1, 1. The main problem will be turning these values to their text representation, and viceversa. You need to keep in mind the following details:

  • Leap years have one extra day.
  • The rule for leap years was "any multiple of 4" until 1582, when it changed from the Julian to the Gregorian calendar and became "multiple of 4 except those that are multiples of 100 unless they are also multiples of 400".
  • The last day of the Julian calendar was Oct 4th, 1582. The next day, first of the Gregorian calendar, was Oct 15th, 1582. 10 days were skipped to make the new calendar match again with the seasons.
  • As stated in the comments, the two rules above vary by country: Papal states and some catholic countries did adopt the new calendar on the stated dates, but many other countries took longer to do so (the last being Turkey in 1926). This means that any date between the papal bull in 1582 and the last adoption in 1926 will be ambiguous without geographical context, and even more complex to process.
  • There is no "year 0": the year before year 1 was year -1, or year 1 BCE.

All of this requires quite elaborate parser and formater functions, but beyond the many case-by-case breakings there isn't really too much complexity (it'd be tedious to code, but quite straight-forward). The use of numbers as the underlying representation ensures correct sorting/comparing for any pair of values.

Knowing this, now it's your choice to take the approach that better fits your needs.

Edurne Pascual
  • 5,560
  • 1
  • 26
  • 31
  • 1
    Thank you for this very insteresting answer. Should I create my own algo for historical date or choose another db but which one ? – user310291 Mar 21 '10 at 16:34
  • 2
    I wish SO allowed a small number of +2 upvotes for exceptionally good answers. Thanks for not only the very useful details but making it an interesting read as well. I have one minor quibble, which is that I think in general "BCE" is preferred over "BC". – eyelidlessness Nov 18 '10 at 07:15
  • 1
    "The last day of the Julian calendar was Oct 4th, 1582" That's only true in certain European countries. The date for the adoption of the Gregorian calendar varies tremendously. See https://en.wikipedia.org/wiki/Gregorian_calendar#Adoption – Dave Cross Mar 24 '17 at 12:00
  • 1
    @DaveCross You are right; I have incorporated the issue into my answer. Thanks for bringing it up. – Edurne Pascual Mar 24 '17 at 14:04
  • @EdurnePascual Is "Turley" a typo for "Turkey"? – Dan Bechard May 16 '18 at 22:54
12

From the documentation:

DATE

A date. The supported range is '1000-01-01' to '9999-12-31'.

Phil Ross
  • 25,590
  • 9
  • 67
  • 77
  • Thank you. So date below 1000 not supported. – user310291 Mar 21 '10 at 15:22
  • 1
    @user284523 Dates before the year 1000 are not supported using the date or datetime datatypes. You could of course store earlier dates using your own encoding as a different datatype (e.g. as a varchar). – Phil Ross Mar 21 '10 at 15:26
  • If I implement my own encoding, it means I'll also have to create dates functions ? Doesn't anyone have that need before I'm surprised to be able to find anything ? – user310291 Mar 21 '10 at 16:36
  • I'm working on the same issue - currently investigating the possibility of using an Old Slavonic calendar system, according to which the current year is 7520 from the time of creation. (=2012 AD). This should be able to handle dates starting from ~5500 BC. Not yet sure what I'll do about months and dates of the week though. Ancient Slavs appear to have had two simultaneous calendars running within each year cycle - a lunar and a solar one. Will post updates – Val Redchenko Mar 21 '12 at 12:51
  • 2
    Just occurred to me - if the supported date range is up to the year 9999, then a simple timeshift should do the trick. Though it is important to shift by number of years divisible by 4 to line up the leap years. – Val Redchenko Mar 21 '12 at 13:05
6

Yes. MySQL dates start in year 1000.

Pablo Santa Cruz
  • 176,835
  • 32
  • 241
  • 292
4

For whatever it's worth, I found that the MySQL DATE field does support dates < 1000 in practice, though the documentation says otherwise. E.g., I was able to enter 325 and it stores as 0325-00-00. A search WHERE table.date < 1000 also gave correct results.

But I am hesitant to rely on the < 1000 dates when they are not officially supported, plus I sometimes need BCE years with more than 4 digits anyway (e.g. 10000 BCE). So separate INT fields for year, month and day (as suggested above) do seem the only choice.

I do wish the DATE type (or perhaps a new HISTDATE type) supported a full range of historical dates - it would be nice to combine three fields into one and simply sort by date instead of having to sort by year, month, day.

Holly
  • 3,601
  • 1
  • 17
  • 23
  • You made an interesting point about the "unofficial" support for these dates. Your suggestion "sorting by CE, date to achieve chronological order" wouldn't work, and may misslead people who could be using your idea: the order you'd get would be all the BCE dates from newest to oldest, followed by all CE dates from oldest to newest. That issue is the only thing that stops me from giving you a +1, so maybe you should consider fixing it. – Edurne Pascual Feb 13 '13 at 14:17
  • You're absolutely right, thank you. I've edited my answer accordingly. – Holly May 03 '13 at 00:44
3

Use SMALLINT for year, so the year will accept from -32768 (BC) to 32768 (AD) As for months and days, use TINYINT UNSIGNED

Most historical events dont have months and days, so you could query like this :

SELECT events FROM history WHERE year='-4990'

Result : 'Noah Ark'

Or : SELECT events FROM history WHERE year='570' AND month='4' AND day='20' return : "Muhammad pbuh was born"

Depending on requirements, you could also add DATETIME column and make it NULL for date before 1000 and vice versa (thus saving some bytes)

biegleux
  • 13,179
  • 11
  • 45
  • 52
3

This is an important and interesting problem which has another solution.

Instead of relying on the database platform to support a potentially infinite number of dates with millisecond precision, rely on an object-oriented programming language compiler and runtime to correctly handle date and time arithmetic.

It is possible to do this using the Java Virtual Machine (JVM), where time is measured in milliseconds relative to midnight, January 1, 1970 UTC (Epoch), by persisting the required value as a long in the database (including negative values), and performing the required conversion/calculation in the component layer after retrieval.

For example:

Date d = new Date(Long.MIN_VALUE);
DateFormat df = new SimpleDateFormat("EEE, d MMM yyyy G HH:mm:ss Z");
System.out.println(df.format(d));

Should show: Sun, 2 Dec 292269055 BC 16:47:04 +0000

This also enables independence of database versions and platforms as it abstracts all date and time arithmetic to the JVM runtime, i.e. changes in database versions and platforms will be much less likely to require re-implementation, if at all.

  • This is an interesting answer, but with a caveat: although this approach would remove dependence on the db system, it introduces dependence on the Java environment; so this is a tradeoff rather than a net gain. Also, keep in mind that dependence on the db is not fully removed: you will need a field type that matches Java's `long`; and the name for such a type may be (slightly) different on different db systems. – Edurne Pascual May 07 '13 at 13:37
2

I had the similar problem and I wanted to continue relay on date fields in the DB to allow me use date range search with accuracy of up-to a day for historic values. (My DB includes date of birth and dates of roman emperors...)

The solution was to add a constant year (example: 3000) to all the dates before adding them to the DB and subtracting the same number before displaying the query results to the users.

If you DB has already some dates value in it, remember to update the exiting value with the new const number.

Yochai
  • 2,783
  • 2
  • 12
  • 8