116

Given a value I want to validate it to check if it is a valid year. My criteria is simple where the value should be an integer with 4 characters. I know this is not the best solution as it will not allow years before 1000 and will allow years such as 5000. This criteria is adequate for my current scenario.

What I came up with is

\d{4}$

While this works it also allows negative values.

How do I ensure that only positive integers are allowed?

Alexis Tyler
  • 1,394
  • 6
  • 30
  • 48
Ranhiru Jude Cooray
  • 19,542
  • 20
  • 83
  • 128
  • fwiw I created a node.js project, [to-regex-range](https://github.com/jonschlinkert/to-regex-range) to automatically create these ranges. It's harder than it might seem if you need to generate the regex to test for a range of years. – jonschlinkert May 28 '17 at 21:25
  • Why limit your validation to 4 digit years? http://longnow.org/ – Dan Temple Feb 27 '19 at 10:53

17 Answers17

224

Years from 1000 to 2999

^[12][0-9]{3}$

For 1900-2099

^(19|20)\d{2}$
r92
  • 2,800
  • 2
  • 19
  • 24
98

You need to add a start anchor ^ as:

^\d{4}$

Your regex \d{4}$ will match strings that end with 4 digits. So input like -1234 will be accepted.

By adding the start anchor you match only those strings that begin and end with 4 digits, which effectively means they must contain only 4 digits.

codaddict
  • 445,704
  • 82
  • 492
  • 529
  • 2
    Damn! Mine was so flawed that it would have even accepted `whateverblahblah2323`. Now I understand why a little learning is dangerous :O – Ranhiru Jude Cooray Dec 07 '10 at 07:21
  • 68
    This will break in the year 10,000. – sferik Sep 03 '12 at 00:14
  • 16
    @sferik: Doesn't matter. The original poster specifically stated he wanted to check for four characters. He did not state he wanted the year 10,000 to be valid input, so accepting `10000` would be a bug. – markusk Feb 01 '15 at 09:01
  • 6
    @sferik: The program will be gone for centuries by then. If not, it is best to worry about 9,000 years in the future. Following the principle of YAGNI, the approach is valid. – Phil Jan 05 '18 at 18:07
  • @Phil not just the program, will be highly doubtful that the human race or the planet will be around at that time. And for sure robots will be doing most of the coding long before that and laughing to each other as they try to rewrite our terrible code. – blissweb Aug 22 '21 at 02:50
22

The "accepted" answer to this question is both incorrect and myopic.

It is incorrect in that it will match strings like 0001, which is not a valid year.

It is myopic in that it will not match any values above 9999. Have we already forgotten the lessons of Y2K? Instead, use the regular expression:

^[1-9]\d{3,}$

If you need to match years in the past, in addition to years in the future, you could use this regular expression to match any positive integer:

^[1-9]\d*$

Even if you don't expect dates from the past, you may want to use this regular expression anyway, just in case someone invents a time machine and wants to take your software back with them.

Note: This regular expression will match all years, including those before the year 1, since they are typically represented with a BC designation instead of a negative integer. Of course, this convention could change over the next few millennia, so your best option is to match any integer—positive or negative—with the following regular expression:

^-?[1-9]\d*$
sferik
  • 1,795
  • 2
  • 15
  • 22
  • 4
    No, it likely won't. But someone (archeologist? historian?) might need to match years for 8000 years ago. :D And Doc Brown might need it... – Jaime Jun 24 '14 at 12:59
  • 1
    i used this to limit range from 1000-9999 ^[1-9]\\d{3}$ thats because the application we have to provide data to, accept 4 digits numbers only :( – MatPag Nov 16 '15 at 11:42
  • Awesome answer. I'd make it the following to accept the year 0 as well: ^(-?[1-9]\d*|0)$ – Kosta Kontos Dec 15 '16 at 14:07
  • I would say 0001 is a valid year. And there is no way in hell this code is gonna be running in the year 2080 let alone 9999. y2k was 1960 looking forward 40 years, not looking forward 7000+ But yeah ... apart from that, some useful tidbits – blissweb Aug 22 '21 at 02:45
  • This will also match `1234567` so better omit the `,` -> `^[1-9]\d{3}$` – nonNumericalFloat May 03 '22 at 12:40
13

This works for 1900 to 2099:

/(?:(?:19|20)[0-9]{2})/
jonschlinkert
  • 10,872
  • 4
  • 43
  • 50
6

Building on @r92 answer, for years 1970-2019:

(19[789]\d|20[01]\d)
Renaud
  • 16,073
  • 6
  • 81
  • 79
  • Your answer allows `197999` – avalanche1 Sep 08 '16 at 16:06
  • I don't think it does... The first part of the regex matches number starting with 19, then any of 7,8 or 9, followed by a SINGLE number. The regex `19[789]\d\d\d` would allow `197999 ` – Renaud Sep 09 '16 at 07:16
  • 1
    `/(19[789]\d|20[01]\d)/.test(1970324) >> true` – avalanche1 Sep 12 '16 at 11:25
  • yes, it will match the first 4 numbers (`1970`), not the last 3. What about `(19[789]\d|20[01]\d)[^0-9]`? That would match `1970 324` but not `1970324` – Renaud Sep 13 '16 at 07:35
  • 1
    I found this one useful for finding the movie year from a filename... in this case we want stuff from 1930s onwards... but we then exclude the 1024 that is added to the end for video quality – Adrian Hum Jan 28 '20 at 23:04
3

To test a year in a string which contains other words along with the year you can use the following regex: \b\d{4}\b

Dhyey
  • 4,275
  • 3
  • 26
  • 33
3

In theory the 4 digit option is right. But in practice it might be better to have 1900-2099 range.

Additionally it need to be non-capturing group. Many comments and answers propose capturing grouping which is not proper IMHO. Because for matching it might work, but for extracting matches using regex it will extract 4 digit numbers and two digit (19 and 20) numbers also because of paranthesis.

This will work for exact matching using non-capturing groups:

(?:19|20)\d{2}

Adil Aliyev
  • 1,159
  • 2
  • 9
  • 22
2

Use;

^(19|[2-9][0-9])\d{2}$ 

for years 1900 - 9999.

No need to worry for 9999 and onwards - A.I. will be doing all programming by then !!! Hehehehe

You can test your regex at https://regex101.com/

Also more info about non-capturing groups ( mentioned in one the comments above ) here http://www.manifold.net/doc/radian/why_do_non-capture_groups_exist_.htm

MarcoZen
  • 1,556
  • 22
  • 27
1

/^\d{4}$/ This will check if a string consists of only 4 numbers. In this scenario, to input a year 989, you can give 0989 instead.

Dayz
  • 269
  • 2
  • 12
1

you can go with sth like [^-]\d{4}$: you prevent the minus sign - to be before your 4 digits.
you can also use ^\d{4}$ with ^ to catch the beginning of the string. It depends on your scenario actually...

pierroz
  • 7,653
  • 9
  • 48
  • 60
0

I use this regex in Java ^(0[1-9]|1[012])[/](0[1-9]|[12][0-9]|3[01])[/](19|[2-9][0-9])[0-9]{2}$

Works from 1900 to 9999

R2Rivs
  • 1
  • 1
0

You could convert your integer into a string. As the minus sign will not match the digits, you will have no negative years.

bluish
  • 26,356
  • 27
  • 122
  • 180
Comradin
  • 194
  • 1
  • 5
0

If you need to match YYYY or YYYYMMDD you can use:

^((?:(?:(?:(?:(?:[1-9]\d)(?:0[48]|[2468][048]|[13579][26])|(?:(?:[2468][048]|[13579][26])00))(?:0?2(?:29)))|(?:(?:[1-9]\d{3})(?:(?:(?:0?[13578]|1[02])(?:31))|(?:(?:0?[13-9]|1[0-2])(?:29|30))|(?:(?:0?[1-9])|(?:1[0-2]))(?:0?[1-9]|1\d|2[0-8])))))|(?:19|20)\d{2})$
  • How can convert YYYYMMDD or DDMMYYYY into YYYY.MM.DD or DD.MM.YYYY. I have string like 20200315 and I want to convert to 2020.03.15 in Dart. Also incoming string might be 17042021 then I need to convert to 17.04.2020 in Dart. Thanks – NTMS Mar 04 '21 at 07:37
0

You can also use this one.

([0-2][0-9]|3[0-1])\/([0-1][0-2])\/(19[789]\d|20[01]\d)
Ranjeet Chouhan
  • 686
  • 5
  • 13
0

In my case I wanted to match a string which ends with a year (4 digits) like this for example:

Oct 2020
Nov 2020
Dec 2020
Jan 2021

It'll return true with this one:

var sheetName = 'Jan 2021';
var yearRegex = new RegExp("\b\d{4}$");
var isMonthSheet = yearRegex.test(sheetName);
Logger.log('isMonthSheet = ' + isMonthSheet);

The code above is used in Apps Script.

Here's the link to test the Regex above: https://regex101.com/r/SzYQLN/1

Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
0

You can try the following to capture valid year from a string:

.*(19\d{2}|20\d{2}).*
greenie
  • 409
  • 3
  • 6
  • 1
    This allows arbitrary text before and after the year, which is not what the question is looking for. – joanis Sep 09 '21 at 19:28
-1

Works from 1950 to 2099 and value is an integer with 4 characters

^(?=.*?(19[56789]|20\d{2}).*)\d{4}$