Days between dates: Difference between revisions
(Realize in F#) |
No edit summary |
||
Line 1,035: | Line 1,035: | ||
Enter date 2: 2019-10-02 |
Enter date 2: 2019-10-02 |
||
There are 18171 days between these dates.</pre> |
There are 18171 days between these dates.</pre> |
||
=={{header|Mathematica}} / {{header|Wolfram Language}}== |
|||
<lang Mathematica>DateDifference["2020-01-01", "2020-03-01"] |
|||
DateDifference["2021-01-01", "2021-03-01"]</lang> |
|||
{{out}} |
|||
<pre>Quantity[60, "Days"] |
|||
Quantity[59, "Days"]</pre> |
|||
=={{header|Nim}}== |
=={{header|Nim}}== |
Revision as of 22:37, 4 June 2021
- Task
Calculate the number of days between two dates.
Date input should be of the form YYYY-MM-DD.
- Motivation
To demonstrate one of the numerous ways this can be done.
Ada
<lang Ada>with Ada.Calendar; with Ada.Text_IO; with Ada.Integer_Text_IO;
with GNAT.Calendar.Time_IO;
procedure Days_Between_Dates is
function Days_Between (Lower_Date : in Ada.Calendar.Time; Higher_Date : in Ada.Calendar.Time) return Integer is use Ada.Calendar; Diff : constant Duration := Higher_Date - Lower_Date; begin return Integer (Diff / Day_Duration'Last); end Days_Between;
procedure Put_Days_Between (Lower_Date : in String; Higher_Date : in String; Comment : in String) is use Ada.Text_IO; use Ada.Integer_Text_IO; use GNAT.Calendar.Time_IO;
Diff : constant Integer := Days_Between (Lower_Date => Value (Lower_Date), Higher_Date => Value (Higher_Date)); begin Put ("Days between " & Lower_Date & " and " & Higher_Date & " is "); Put (Diff, Width => 5); Put (" days -- "); Put (Comment); New_Line; end Put_Days_Between;
begin
Put_Days_Between ("1995-11-21", "1995-11-21", "Identical dates"); Put_Days_Between ("2019-01-01", "2019-01-02", "Positive span"); Put_Days_Between ("2019-01-02", "2019-01-01", "Negative span"); Put_Days_Between ("2019-01-01", "2019-03-01", "Non-leap year"); Put_Days_Between ("2020-01-01", "2020-03-01", "Leap year"); Put_Days_Between ("1902-01-01", "1968-12-25", "Past"); Put_Days_Between ("2090-01-01", "2098-12-25", "Future"); Put_Days_Between ("1902-01-01", "2098-12-25", "Long span");
end Days_Between_Dates;</lang>
- Output:
Days between 1995-11-21 and 1995-11-21 is 0 days -- Identical dates Days between 2019-01-01 and 2019-01-02 is 1 days -- Positive span Days between 2019-01-02 and 2019-01-01 is -1 days -- Negative span Days between 2019-01-01 and 2019-03-01 is 59 days -- Non-leap year Days between 2020-01-01 and 2020-03-01 is 60 days -- Leap year Days between 1902-01-01 and 1968-12-25 is 24465 days -- Past Days between 2090-01-01 and 2098-12-25 is 3280 days -- Future Days between 1902-01-01 and 2098-12-25 is 71947 days -- Long span
AppleScript
<lang applescript>on daysBetweenDates(date1, date2)
considering numeric strings -- Allows for leading zeros having been omitted. if (date1 = date2) then return date1 & " and " & date2 & " are the same date" end considering -- Get the components of each date. set astid to AppleScript's text item delimiters set AppleScript's text item delimiters to "-" set {y1, m1, d1} to date1's text items set {y2, m2, d2} to date2's text items set AppleScript's text item delimiters to astid -- Derive AppleScript date objects. -- The best way to do this generally is to use the 'current date' function to obtain a date object -- and then to set the properties of the result (or of a copy) to the required values. -- The initial setting of the day values to 1 is to prevent overflow due to possibly -- incompatible day and month values during the sequential setting of the properties. -- The integer values set here are automatically coerced from the text values obtained above. tell (current date) to set {its day, its year, its month, its day, its time, firstDate} to {1, y1, m1, d1, 0, it} copy firstDate to secondDate tell secondDate to set {its day, its year, its month, its day} to {1, y2, m2, d2} -- Do the math. set daysDifference to (firstDate - secondDate) div days -- Format some output. if (daysDifference > 0) then return date1 & " comes " & daysDifference & " day" & item (((daysDifference is 1) as integer) + 1) of {"s", ""} & ¬ " after " & date2 else return date1 & " comes " & -daysDifference & " day" & item (((daysDifference is -1) as integer) + 1) of {"s", ""} & ¬ " before " & date2 end if
end daysBetweenDates
return daysBetweenDates("2020-04-11", "2001-01-01") & linefeed & ¬
daysBetweenDates("2020-04-11", "2020-04-12") & linefeed & ¬ daysBetweenDates("2020-04-11", "2020-04-11")</lang>
- Output:
"2020-04-11 comes 7040 days after 2001-01-01 2020-04-11 comes 1 day before 2020-04-12 2020-04-11 and 2020-04-11 are the same date"
Or, composing a function from reusable generics, and drawing on NSISO8601DateFormatter:
<lang applescript>use AppleScript version "2.4" use framework "Foundation" use scripting additions
-- daysBetween :: String -> String -> Int
on daysBetween(iso8601From, iso8601To)
set midnight to "T00:00:00+00:00" ((dateFromISO8601(iso8601To & midnight) - ¬ dateFromISO8601(iso8601From & midnight)) / 86400) as integer
end daysBetween
-- dateFromISO8601 :: String -> Date
on dateFromISO8601(isoDateString)
set ca to current application tell ca's NSISO8601DateFormatter's alloc's init() set its formatOptions to ¬ (ca's NSISO8601DateFormatWithInternetDateTime as integer) (its dateFromString:(isoDateString)) as date end tell
end dateFromISO8601
TEST----------------------------
on run
script test on |λ|(ab) set {a, b} to ab set delta to daysBetween(a, b) (a & " -> " & b & " -> " & ¬ justifyRight(5, space, delta as string)) & ¬ pluralize(delta, " day") end |λ| end script unlines(map(test, {¬ {"2020-04-11", "2001-01-01"}, ¬ {"2020-04-11", "2020-04-12"}, ¬ {"2020-04-11", "2020-04-11"}, ¬ {"2019-01-01", "2019-09-30"}}))
end run
GENERIC FUNCTIONS ---------------------
-- Absolute value. -- abs :: Num -> Num on abs(x)
if 0 > x then -x else x end if
end abs
-- justifyRight :: Int -> Char -> String -> String
on justifyRight(n, cFiller, strText)
if n > length of strText then text -n thru -1 of ((replicate(n, cFiller) as text) & strText) else strText end if
end justifyRight
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
-- The list obtained by applying f -- to each element of xs. tell mReturn(f) set lng to length of xs set lst to {} repeat with i from 1 to lng set end of lst to |λ|(item i of xs, i, xs) end repeat return lst end tell
end map
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
-- 2nd class handler function lifted into 1st class script wrapper. if script is class of f then f else script property |λ| : f end script end if
end mReturn
-- pluralize :: Int -> String -> String
on pluralize(n, s)
set m to abs(n) if 0 = m or 2 ≤ m then s & "s" else s end if
end pluralize
-- replicate :: Int -> String -> String
on replicate(n, s)
set out to "" if n < 1 then return out set dbl to s repeat while (n > 1) if (n mod 2) > 0 then set out to out & dbl set n to (n div 2) set dbl to (dbl & dbl) end repeat return out & dbl
end replicate
-- unlines :: [String] -> String
on unlines(xs)
-- A single string formed by the intercalation -- of a list of strings with the newline character. set {dlm, my text item delimiters} to ¬ {my text item delimiters, linefeed} set str to xs as text set my text item delimiters to dlm str
end unlines</lang>
- Output:
2020-04-11 -> 2001-01-01 -> -7040 days 2020-04-11 -> 2020-04-12 -> 1 day 2020-04-11 -> 2020-04-11 -> 0 days 2019-01-01 -> 2019-09-30 -> 272 days
Arturo
<lang rebol>daysBetweenDates: function [startDate, endDate][
a: to :date.format: "dd/MM/yyyy" startDate b: to :date.format: "dd/MM/yyyy" endDate
return abs b\days - a\days
]
print [
"days between the two dates:" daysBetweenDates "01/01/2019" "19/10/2019"
]</lang>
- Output:
days between the two dates: 291
AWK
<lang AWK>
- syntax: GAWK -f DAYS_BETWEEN_DATES.AWK
BEGIN {
regexp = "^....-..-..$" # YYYY-MM-DD main("1969-12-31","1970-01-01","builtin has bad POSIX start date") main("1970-01-01","2038-01-19","builtin has bad POSIX stop date") main("1970-01-01","2019-10-02","format OK") main("1970-01-01","2019/10/02","format NG") main("1995-11-21","1995-11-21","identical dates") main("2019-01-01","2019-01-02","positive date") main("2019-01-02","2019-01-01","negative date") main("2019-01-01","2019-03-01","non-leap year") main("2020-01-01","2020-03-01","leap year") exit(0)
} function main(date1,date2,comment, d1,d2,diff) {
printf("\t%s\n",comment) d1 = days_builtin(date1) d2 = days_builtin(date2) diff = (d1 == "" || d2 == "") ? "error" : d2-d1 printf("builtin %10s to %10s = %s\n",date1,date2,diff) d1 = days_generic(date1) d2 = days_generic(date2) diff = (d1 == "" || d2 == "") ? "error" : d2-d1 printf("generic %10s to %10s = %s\n",date1,date2,diff)
} function days_builtin(ymd) { # use gawk builtin
if (ymd !~ regexp) { return("") } if (ymd < "1970-01-01" || ymd > "2038-01-18") { return("") } # outside POSIX range gsub(/-/," ",ymd) return(int(mktime(sprintf("%s 0 0 0",ymd)) / (60*60*24)))
} function days_generic(ymd, d,m,y,result) { # use Python formula
if (ymd !~ regexp) { return("") } y = substr(ymd,1,4) m = substr(ymd,6,2) d = substr(ymd,9,2) m = (m + 9) % 12 y = int(y - int(m/10)) result = 365*y + int(y/4) - int(y/100) + int(y/400) + int((m*306+5)/10) + (d-1) return(result)
} </lang>
- Output:
builtin has bad POSIX start date builtin 1969-12-31 to 1970-01-01 = error generic 1969-12-31 to 1970-01-01 = 1 builtin has bad POSIX stop date builtin 1970-01-01 to 2038-01-19 = error generic 1970-01-01 to 2038-01-19 = 24855 format OK builtin 1970-01-01 to 2019-10-02 = 18171 generic 1970-01-01 to 2019-10-02 = 18171 format NG builtin 1970-01-01 to 2019/10/02 = error generic 1970-01-01 to 2019/10/02 = error identical dates builtin 1995-11-21 to 1995-11-21 = 0 generic 1995-11-21 to 1995-11-21 = 0 positive date builtin 2019-01-01 to 2019-01-02 = 1 generic 2019-01-01 to 2019-01-02 = 1 negative date builtin 2019-01-02 to 2019-01-01 = -1 generic 2019-01-02 to 2019-01-01 = -1 non-leap year builtin 2019-01-01 to 2019-03-01 = 59 generic 2019-01-01 to 2019-03-01 = 59 leap year builtin 2020-01-01 to 2020-03-01 = 60 generic 2020-01-01 to 2020-03-01 = 60
C
<lang C>
- include<stdbool.h>
- include<string.h>
- include<stdio.h>
typedef struct{
int year, month, day;
}date;
date extractDate(char* str){
return (date){.year = 1000 * (str[0]-'0') + 100 * (str[1]-'0') + 10 * (str[2]-'0') + (str[3]-'0'), .month = 10*(str[5]-'0') + (str[6]-'0'), .day = 10*(str[8]-'0') + (str[9]-'0')};
}
bool isValidDate(char* str){
date newDate; if(strlen(str)!=10 && str[4]!='-' && str[7]!='-'){ return false; }
newDate = extractDate(str);
if(newDate.year<=0 || newDate.month<=0 || newDate.day<=0 || newDate.month>12 || (newDate.month==2 && newDate.day>29) || ((newDate.month==1 || newDate.month==3 || newDate.month==5 || newDate.month==7 || newDate.month==8 || newDate.month==10 || newDate.month==12) && newDate.day>31) || newDate.day>30 || (newDate.year%4==0 && newDate.month==2 && newDate.month>28)){ return false; }
return true;
}
int diffDays(date date1,date date2){
int days1, days2; date1.month = (date1.month + 9)%12; date1.year = date1.year - date1.month/10;
date2.month = (date2.month + 9)%12; date2.year = date2.year - date2.month/10;
days1 = 365*date1.year + date1.year/4 - date1.year/100 + date1.year/400 + (date1.month*306 + 5)/10 + ( date1.day - 1 ); days2 = 365*date2.year + date2.year/4 - date2.year/100 + date2.year/400 + (date2.month*306 + 5)/10 + ( date2.day - 1 );
return days2 - days1;
}
int main(int argc,char** argv) {
if(argc!=3){ return printf("Usage : %s <yyyy-mm-dd> <yyyy-mm-dd>",argv[0]); }
if(isValidDate(argv[1])&&isValidDate(argv[2]) == false){ return printf("Dates are invalid.\n"); }
printf("Days Difference : %d\n", diffDays(extractDate(argv[1]),extractDate(argv[2])));
return 0;
} </lang> Output :
abhishek_ghosh@Azure:~/doodles$ ./a.out 2019-01-01 2019-12-02 Days Difference : 335
C++
<lang cpp>#include <iomanip>
- include <iostream>
class Date { private:
int year, month, day;
public:
Date(std::string str) { if (isValidDate(str)) { year = atoi(&str[0]); month = atoi(&str[5]); day = atoi(&str[8]); } else { throw std::exception("Invalid date"); } }
int getYear() { return year; }
int getMonth() { return month; }
int getDay() { return day; }
// YYYY-MM-DD static bool isValidDate(std::string str) { if (str.length() != 10 || str[4] != '-' || str[7] != '-') { return false; }
if (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || !isdigit(str[3])) { return false; // the year is not valid } if (!isdigit(str[5]) || !isdigit(str[6])) { return false; // the month is not valid } if (!isdigit(str[8]) || !isdigit(str[9])) { return false; // the day is not valid }
int year = atoi(&str[0]); int month = atoi(&str[5]); int day = atoi(&str[8]);
// quick checks if (year <= 0 || month <= 0 || day <= 0) { return false; } if (month > 12) { return false; }
switch (month) { case 2: if (day > 29) { return false; } if (!isLeapYear(year) && day == 29) { return false; } break; case 1: case 3: case 5: case 7: case 8: case 10: case 12: if (day > 31) { return false; } break; default: if (day > 30) { return false; } break; }
return true; }
static bool isLeapYear(int year) { if (year > 1582) { return ((year % 4 == 0) && (year % 100 > 0)) || (year % 400 == 0); } if (year > 10) { return year % 4 == 0; } // not bothering with earlier leap years return false; }
friend std::ostream &operator<<(std::ostream &, Date &);
};
std::ostream &operator<<(std::ostream &os, Date &d) {
os << std::setfill('0') << std::setw(4) << d.year << '-'; os << std::setfill('0') << std::setw(2) << d.month << '-'; os << std::setfill('0') << std::setw(2) << d.day; return os;
}
int diffDays(Date date1, Date date2) {
int d1m = (date1.getMonth() + 9) % 12; int d1y = date1.getYear() - d1m / 10;
int d2m = (date2.getMonth() + 9) % 12; int d2y = date2.getYear() - d2m / 10;
int days1 = 365 * d1y + d1y / 4 - d1y / 100 + d1y / 400 + (d1m * 306 + 5) / 10 + (date1.getDay() - 1); int days2 = 365 * d2y + d2y / 4 - d2y / 100 + d2y / 400 + (d2m * 306 + 5) / 10 + (date2.getDay() - 1);
return days2 - days1;
}
int main() {
std::string ds1 = "2019-01-01"; std::string ds2 = "2019-12-02";
if (Date::isValidDate(ds1) && Date::isValidDate(ds2)) { Date d1(ds1); Date d2(ds2); std::cout << "Days difference : " << diffDays(d1, d2); } else { std::cout << "Dates are invalid.\n"; }
return 0;
}</lang>
- Output:
Days difference : 335
Alternative using Boost
<lang cpp>#include <cstdlib>
- include <iostream>
- include <boost/date_time/gregorian/gregorian.hpp>
int main(int argc, char** argv) {
using namespace boost::gregorian; if (argc != 3) { std::cerr << "usage: " << argv[0] << " start-date end-date\n"; return EXIT_FAILURE; } try { date start_date(from_simple_string(argv[1])); date end_date(from_simple_string(argv[2])); std::cout << end_date - start_date << '\n'; } catch (const std::exception& ex) { std::cerr << ex.what() << '\n'; return EXIT_FAILURE; } return EXIT_SUCCESS;
}</lang>
- Output:
./days_between_dates 2020-01-01 2020-09-06 249
C#
<lang csharp>using System; using System.Globalization;
public class Program {
public static void Main() => WriteLine(DateDiff("1970-01-01", "2019-10-18"));
public static int DateDiff(string d1, string d2) { var a = DateTime.ParseExact(d1, "yyyy-MM-dd", CultureInfo.InvariantCulture); var b = DateTime.ParseExact(d2, "yyyy-MM-dd", CultureInfo.InvariantCulture); return (int)(b - a).TotalDays; }
}</lang>
- Output:
18187
COBOL
<lang COBOL>COBOL *> days-between
*> Tectonics: cobc -xj days-between.cob
identification division. program-id. days-between.
procedure division. compute tally = function integer-of-formatted-date('YYYY-MM-DD', '2019-11-24') - function integer-of-formatted-date('YYYY-MM-DD', '2000-01-01') display tally
compute tally = function integer-of-formatted-date('YYYYMMDD', '20191124') - function integer-of-formatted-date('YYYYMMDD', '20000101') display tally
goback. end program days-between.</lang>
- Output:
prompt$ cobc -xj days-between-dates.cob 07267 07267
D
<lang d>import std.datetime.date; import std.stdio;
void main() {
auto fromDate = Date.fromISOExtString("2019-01-01"); auto toDate = Date.fromISOExtString("2019-10-07"); auto diff = toDate - fromDate; writeln("Number of days between ", fromDate, " and ", toDate, ": ", diff.total!"days");
}</lang>
- Output:
Number of days between 2019-Jan-01 and 2019-Oct-07: 279
Delphi
<lang Delphi> program Days_between_dates;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
function CreateFormat(fmt: string; Delimiter: Char): TFormatSettings; begin
Result := TFormatSettings.Create(); with Result do begin DateSeparator := Delimiter; ShortDateFormat := fmt; end;
end;
function DaysBetween(Date1, Date2: string): Integer; var
dt1, dt2: TDateTime; fmt: TFormatSettings;
begin
fmt := CreateFormat('yyyy-mm-dd', '-'); dt1 := StrToDate(Date1, fmt); dt2 := StrToDate(Date2, fmt); Result := Trunc(dt2 - dt1);
end;
begin
Writeln(DaysBetween('1970-01-01', '2019-10-18')); readln;
end.</lang>
- Output:
18187
Erlang
<lang erlang>
-module(daysbetween). -export([between/2,dateToInts/2]).
% Return Year or Month or Date from datestring dateToInts(String, POS) ->
list_to_integer( lists:nth( POS, string:tokens(String, "-") ) ).
% Alternative form of above % dateToInts(String,POS) -> % list_to_integer( lists:nth( POS, re:split(String ,"-", [{return,list},trim]) ) ).
% Return the number of days between dates formatted "2019-09-30" between(DateOne,DateTwo) ->
L = [1,2,3], [Y1,M1,D1] = [ dateToInts(DateOne,X) || X <- L], [Y2,M2,D2] = [ dateToInts(DateTwo,X) || X <- L], GregOne = calendar:date_to_gregorian_days(Y1,M1,D1), GregTwo = calendar:date_to_gregorian_days(Y2,M2,D2), GregTwo - GregOne.
</lang>
- Output:
erlang shell:
30> c(daysbetween). c(daysbetween). {ok,daysbetween} 31> daysbetween:between("2019-01-01", "2019-09-30"). daysbetween:between("2019-01-01", "2019-09-30"). 272
Excel
LAMBDA
Excel dates are numbers counting days since the start of January 1900, and arithmetic operations can be applied to them directly.
(Unless entered as strings, they differ from other numbers only in the display format applied to the containing cell).
The lambda expression below maps over an array of date strings, defining a new array of the differences, in units of one day, between today's date and those earlier dates.
(See LAMBDA: The ultimate Excel worksheet function)
- Output:
The formula in cell B2 defines the array of day counts which populate the range B2:B5
fx | =LAMBDA(dateString, TODAY() - DATEVALUE(dateString) )(C2#) | ||||
---|---|---|---|---|---|
A | B | C | D | ||
1 | Difference in days | Earlier date | Today | ||
2 | 39020 | 1914-07-28 | 2021-05-27 | ||
3 | 37088 | 1919-11-11 | |||
4 | 29916 | 1939-07-01 | |||
5 | 27661 | 1945-09-02 |
Alternatively, we can express the same mapping over the whole C2# array by directly writing:
fx | = TODAY() - DATEVALUE(C2#) | ||||
---|---|---|---|---|---|
A | B | C | D | ||
1 | Difference in days | Earlier date | Today | ||
2 | 39020 | 1914-07-28 | 2021-05-27 | ||
3 | 37088 | 1919-11-11 | |||
4 | 29916 | 1939-07-01 | |||
5 | 27661 | 1945-09-02 |
F#
<lang fsharp> // Days between dates: Nigel Galloway. June 3rd., 2021 let n,g=System.DateTime.Parse("1792-9-22"),System.DateTime.Parse("1805-12-31") printfn "There are %d days between %d-%d-%d and %d-%d-%d" (g-n).Days n.Year n.Month n.Day g.Year g.Month g.Day </lang>
- Output:
There are 4847 days between 1792-9-22 and 1805-12-31
Factor
Factor supports the addition and subtraction of timestamps and durations with the time+
and time-
words.
<lang factor>USING: calendar calendar.parser kernel math prettyprint ;
- days-between ( ymd-str ymd-str -- n )
[ ymd>timestamp ] bi@ time- duration>days abs ;
"2019-01-01" "2019-09-30" days-between . "2016-01-01" "2016-09-30" days-between . ! leap year</lang>
- Output:
272 273
Frink
Frink handles dates and intervals between dates robustly, including time zones. The sample below could use minutes
or seconds
instead of days
.
Frink can even track leap seconds as they are added to the calendar if desired. The code d1-d2
in the sample below could be replaced by subtractLeap[d1,d2]
to obtain exact counts of seconds between dates.
See Frink's Date/Time Handling documentation to see how easy it is to work with dates, times, timezones, calendrical systems, and even leap seconds correctly and easily.
<lang frink>d1 = # 2020-12-25 # d2 = # 2020-12-06 # println[d1-d2 -> days]</lang>
- Output:
19
Go
<lang go>package main
import (
"fmt" "log" "time"
)
const layout = "2006-01-02" // template for time.Parse
// Parameters assumed to be in YYYY-MM-DD format. func daysBetween(date1, date2 string) int {
t1, err := time.Parse(layout, date1) check(err) t2, err := time.Parse(layout, date2) check(err) days := int(t1.Sub(t2).Hours() / 24) if days < 0 { days = -days } return days
}
func check(err error) {
if err != nil { log.Fatal(err) }
}
func main() {
date1, date2 := "2019-01-01", "2019-09-30" days := daysBetween(date1, date2) fmt.Printf("There are %d days between %s and %s\n", days, date1, date2)
date1, date2 = "2015-12-31", "2016-09-30" days = daysBetween(date1, date2) fmt.Printf("There are %d days between %s and %s\n", days, date1, date2)
}</lang>
- Output:
There are 272 days between 2019-01-01 and 2019-09-30 There are 274 days between 2015-12-31 and 2016-09-30
Groovy
<lang groovy>import java.time.LocalDate
def fromDate = LocalDate.parse("2019-01-01") def toDate = LocalDate.parse("2019-10-19") def diff = fromDate - toDate println "Number of days between ${fromDate} and ${toDate}: ${diff}"</lang>
- Output:
Number of days between 2019-01-01 and 2019-10-19: 291
Haskell
<lang Haskell>import Data.Time (Day) import Data.Time.Calendar (diffDays) import Data.Time.Format (parseTimeM,defaultTimeLocale)
main = do
putStrLn $ task "2019-01-01" "2019-09-30" putStrLn $ task "2015-12-31" "2016-09-30"
task :: String -> String -> String task xs ys = "There are " ++ (show $ betweenDays xs ys) ++ " days between " ++ xs ++ " and " ++ ys ++ "."
betweenDays :: String -> String -> Integer betweenDays date1 date2 = go (stringToDay date1) (stringToDay date2)
where go (Just x) (Just y) = diffDays y x go Nothing _ = error "Exception: Bad format first date" go _ Nothing = error "Exception: Bad format second date"
stringToDay :: String -> Maybe Day stringToDay date = parseTimeM True defaultTimeLocale "%Y-%-m-%-d" date</lang>
- Output:
There are 272 days between 2019-01-01 and 2019-09-30. There are 274 days between 2015-12-31 and 2016-09-30.
J
require'~addons/types/datetime/datetime.ijs' 2021 03 16 daysDiff 1960 05 04 22231 vectorize=: [: evaluate hyphen_to_space hyphen_to_space=: (=&'-')`(,:&' ')} evaluate=: ". but_first=: & '2021-03-16' daysDiff but_first vectorize '1960-05-04' 22231
Java
<lang java>import java.time.LocalDate; import java.time.temporal.ChronoUnit;
public class DaysBetweenDates {
public static void main(String[] args) { LocalDate fromDate = LocalDate.parse("2019-01-01"); LocalDate toDate = LocalDate.parse("2019-10-19"); long diff = ChronoUnit.DAYS.between(fromDate, toDate); System.out.printf("Number of days between %s and %s: %d\n", fromDate, toDate, diff); }
}</lang>
- Output:
Number of days between 2019-01-01 and 2019-10-19: 291
Julia
<lang julia>using Dates
@show Day(DateTime("2019-09-30") - DateTime("2019-01-01"))
@show Day(DateTime("2019-03-01") - DateTime("2019-02-01"))
@show Day(DateTime("2020-03-01") - DateTime("2020-02-01"))
@show Day(DateTime("2029-03-29") - DateTime("2019-03-29"))
</lang>
- Output:
Day(DateTime("2019-09-30") - DateTime("2019-01-01")) = 272 days Day(DateTime("2019-03-01") - DateTime("2019-02-01")) = 28 days Day(DateTime("2020-03-01") - DateTime("2020-02-01")) = 29 days Day(DateTime("2029-03-29") - DateTime("2019-03-29")) = 3653 days
Kotlin
<lang scala>import java.time.LocalDate import java.time.temporal.ChronoUnit
fun main() {
val fromDate = LocalDate.parse("2019-01-01") val toDate = LocalDate.parse("2019-10-19") val diff = ChronoUnit.DAYS.between(fromDate, toDate) println("Number of days between $fromDate and $toDate: $diff")
}</lang>
- Output:
Number of days between 2019-01-01 and 2019-10-19: 291
Lua
This uses os.difftime to compare two Epoch times. Not to be used with dates before 1970. <lang lua>SECONDS_IN_A_DAY = 60 * 60 * 24
-- Convert date string as YYYY-MM-DD to Epoch time. function parseDate (str)
local y, m, d = string.match(str, "(%d+)-(%d+)-(%d+)") return os.time({year = y, month = m, day = d})
end
-- Main procedure io.write("Enter date 1: ") local d1 = parseDate(io.read()) io.write("Enter date 2: ") local d2 = parseDate(io.read()) local diff = math.ceil(os.difftime(d2, d1) / SECONDS_IN_A_DAY) print("There are " .. diff .. " days between these dates.")</lang>
- Output:
Enter date 1: 1970-01-01 Enter date 2: 2019-10-02 There are 18171 days between these dates.
Mathematica / Wolfram Language
<lang Mathematica>DateDifference["2020-01-01", "2020-03-01"] DateDifference["2021-01-01", "2021-03-01"]</lang>
- Output:
Quantity[60, "Days"] Quantity[59, "Days"]
Nim
<lang Nim>import times
proc daysBetween(date1, date2: string): int64 =
const Fmt = initTimeFormat("yyyy-MM-dd") (date2.parse(Fmt, utc()) - date1.parse(Fmt, utc())).inDays
const Dates = [("1995-11-21","1995-11-21"),
("2019-01-01","2019-01-02"), ("2019-01-02","2019-01-01"), ("2019-01-01","2019-03-01"), ("2020-01-01","2020-03-01"), ("1902-01-01","1968-12-25"), ("2090-01-01","2098-12-25")]
for (date1, date2) in Dates:
echo "Days between ", date1, " and ", date2, ": ", daysBetween(date1, date2)</lang>
- Output:
Days between 1995-11-21 and 1995-11-21: 0 Days between 2019-01-01 and 2019-01-02: 1 Days between 2019-01-02 and 2019-01-01: -1 Days between 2019-01-01 and 2019-03-01: 59 Days between 2020-01-01 and 2020-03-01: 60 Days between 1902-01-01 and 1968-12-25: 24465 Days between 2090-01-01 and 2098-12-25: 3280
Perl
Would not reinvent this wheel. <lang perl>use feature 'say'; use Date::Calc qw(Delta_Days);
say Delta_Days(2018,7,13, 2019,9,13); # triskaidekaphobia say Delta_Days(1900,1,1, 2000,1,1); # a century say Delta_Days(2000,1,1, 2100,1,1); # another, with one extra leap day say Delta_Days(2020,1,1, 2019,10,1); # backwards in time say Delta_Days(2019,2,29, 2019,3,1); # croaks</lang>
- Output:
427 36524 36525 -92 Date::Calc::PP::Delta_Days(): Date::Calc::Delta_Days(): not a valid date at Days_between_dates line 10
Phix
include builtins\timedate.e -- specify as many or as few permitted formats as you like: set_timedate_formats({"YYYY-MM-DD","DD/MM/YYYY","YYYY/MM/DD"}) constant SECONDS_TO_DAYS = 60*60*24 procedure test(string d1, d2, desc="") timedate td1 = parse_date_string(d1), td2 = parse_date_string(d2) atom s = timedate_diff(td1,td2,DT_DAY), d = s/SECONDS_TO_DAYS string e = elapsed(s)&desc printf(1,"Days between %s and %s: %d [%s]\n",{d1,d2,d,e}) end procedure test("1969-12-31","1970-01-01") test("1995-11-21","1995-11-21",", same date") test("2019-01-02","2019-01-01",", negative date") test("2019-01-01","2019-03-01",", non-leap year") test("2020-01-01","2020-03-01",", leap year") test("1970-01-01", "2019/10/18") test("1970-01-01", "18/10/2019")
As shown, timedate_diff() can optionally round to the nearest whole number of days [else omit DT_DAY].
Note that elapsed() assumes all years are exactly 365 days, and in no way takes leap years into consideration
(as opposed, of course, to timedate_diff() which handles them flawlessly), not that you sh/c/would ever use the
string output of elapsed() in any further calculations anyway.
- Output:
Days between 1969-12-31 and 1970-01-01: 1 [1 day] Days between 1995-11-21 and 1995-11-21: 0 [0s, same date] Days between 2019-01-02 and 2019-01-01: -1 [minus 1 day, negative date] Days between 2019-01-01 and 2019-03-01: 59 [59 days, non-leap year] Days between 2020-01-01 and 2020-03-01: 60 [60 days, leap year] Days between 1970-01-01 and 2019/10/18: 18187 [49 years, 302 days] Days between 1970-01-01 and 18/10/2019: 18187 [49 years, 302 days]
PicoLisp
<lang PicoLisp>(de diffDates (A B)
(abs (- ($dat A "-") ($dat B "-"))) )
(println (diffDates "2019-1-1" "2019-9-30")) (println (diffDates "2015-12-31" "2016-09-30"))</lang>
- Output:
272 274
Python
<lang python>
- !/usr/bin/python
import sys
Difference between two dates = g(y2,m2,d2) - g(y1,m1,d1)
Where g() gives us the Gregorian Calendar Day Inspired by discussion at: https://stackoverflow.com/questions/12862226/the-implementation-of-calculating-the-number-of-days-between-2-dates
def days( y,m,d ):
input year and month are shifted to begin the year in march m = (m + 9) % 12 y = y - m/10
with (m*306 + 5)/10 the number of days from march 1 to the current 'm' month result = 365*y + y/4 - y/100 + y/400 + (m*306 + 5)/10 + ( d - 1 ) return result
def diff(one,two):
[y1,m1,d1] = one.split('-') [y2,m2,d2] = two.split('-') # strings to integers year2 = days( int(y2),int(m2),int(d2)) year1 = days( int(y1), int(m1), int(d1) ) return year2 - year1
if __name__ == "__main__":
one = sys.argv[1] two = sys.argv[2] print diff(one,two)
</lang>
- Output:
python days-between.py 2019-01-01 2019-09-30 272
Raku
(formerly Perl 6) Dates are first class objects in Raku and may have arithmetic in days done directly on them. <lang perl6>say Date.new('2019-09-30') - Date.new('2019-01-01');
say Date.new('2019-03-01') - Date.new('2019-02-01');
say Date.new('2020-03-01') - Date.new('2020-02-01');
say Date.new('2029-03-29') - Date.new('2019-03-29');
say Date.new('2019-01-01') + 90;
say Date.new('2020-01-01') + 90;
say Date.new('2019-02-29') + 30;
CATCH { default { .message.say; exit; } };</lang>
272 28 29 3653 2019-04-01 2020-03-31 Day out of range. Is: 29, should be in 1..28
REBOL
REBOL accepts a multitude of lexically recognized date! formats. date! is a builtin datatype. Slashes or dashes, year-month-day, day/month/year, or dd/monthname/year, etc. Math on dates defaults to days.
prompt$ rebol -q >> 2019-11-24 - 2000-01-01 == 7267 >> 2019-nov-24 - 01-jan-2000 == 7267
REXX
bare bones version
Programming note: the B (Base) an option for the date BIF which indicates to compute the number of
days since the beginning of the Gregorian calendar, and I which is the option that indicates the date is in
the ISO (International Standards Organization standard 8601:2004) format.
<lang rexx>/*REXX program computes the number of days between two dates in the form of YYYY-MM-DD */
parse arg $1 $2 . /*get 2 arguments (dates) from the C.L.*/
say abs( date('B',$1,"I") - date('B',$2,"I") ) ' days between ' $1 " and " $2
/*stick a fork in it, we're all done. */</lang>
- output when using the inputs of: 2019-10-02 2000-01-01
7214 days between 2019-10-02 and 2000-01-01
supports more variations
This REXX version supports more variations in the date format (allows a single digit month and/or day), as well as
allowing a single asterisk (*) to be used for a date (which signifies that the current date is to be used).
The dates may be specified in the following formats:
, (a comma) indicates today's date * (an asterisk) indicates today's date yyyy-mm-dd where yyyy may be a 2- or 4-digit year, mm may be a 1- or 2-digit month, dd may be a 1- or 2-digit day of month mm/dd/yyyy (as above) mm/dd (as above), but the current year is assumed dd\mm\yyyy (as above) dd\mm (as above), but the current year is assumed
Commas (,) are inserted into numbers where appropriate.
Also, more informative error messages are generated. <lang rexx>/*REXX program computes the number of days between two dates in the form of YYYY-MM-DD */ parse arg $.1 $.2 _ . 1 . . xtra /*obtain two arguments from the C.L. */ seps= '/-\'; yr.= .; mon.= .; dd.= . /*define the defaults for both dates. */
do a=1 for 2 /*process both of the specified dates. */ if $.a== | $.a=="*" | $.a==',' then $.a= date("I") do s=1 for length(seps) /*process a specified date by separator*/ sep= substr(seps, s, 1) /*obtain one of the supported sep char.*/ if pos(sep, $.a)\==0 then call conv $.a /*parse the date string.*/ end /*s*/ end /*a*/
?.1= '1st' ?.2= '2nd' if _ \== then call err "too many arguments specified: " xtra dy.= 31 /*default number of days for all months*/ parse value 30 with dy.4 1 dy.6 1 dy.9 1 dy.11 /*define 30─day months, Feb. is special*/ @notCorr= "isn't in a support date format: " /*used for a literal for an error msg. */
do j=1 for 2 /*examine both dates for correct format*/ if $.j == then call err ?.j "date was not specified." if length(yr.j)==0 then call err ?.j "year" @notCorr '(missing)' if isDec(yr.j) then call err ?.j "year" @notCorr '(has a non─decimal digit)' if yr.j<1 | yr.j>9999 then call err ?.j "year" @notCorr '(not in the range 1──►9999)' if length(mon.j)==0 then call err ?.j "month" @notCorr '(missing)' if isDec(mon.j) then call err ?.j "month" @notCorr '(has a non─decimal digit)' if mon.j<1 | mon.j>12 then call err ?.j "month" @notCorr '(not in the range 1──►12)' if length(dd.j)==0 then call err ?.j "day" @notCorr '(missing)' if isDec(dd.j) then call err ?.j "day" @notCorr '(has a non─decimal digit)' mo= mon.j if leapYr(yr.j) then dy.2= 29 /*Is it a leapyear? Use 29 days for Feb*/ else dy.2= 28 /*Isn't " " " 28 " " " */ if dd.j<1 | dd.j>dy.mo then call err ?.j "day" @notCorr '(day in month is invalid)'
yr.j= right( yr.j +0, 4, 0) /*force YYYY to be four decimal digits.*/ mon.j= right(mon.j +0, 2, 0) /* " MON " " two " " */ dd.j= right( dd.j +0, 2, 0) /* " DD " " " " " */ $.j= yr.j'-'mon.j"-"dd.j /*reconstitute a date from above parts.*/ end /*j*/
between= abs( date('B', $.1, "I") - date('B', $.2, "I") ) /* # days between dates.*/ parse source . how . /*determine how invoked.*/ if how='COMMAND' then say commas(between) ' days between ' $.1 " and " $.2 exit between /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ commas: parse arg _; do c_=length(_)-3 to 1 by -3; _=insert(',', _, c_); end; return _ err: say; say '***error*** ' arg(1); exit 13 /*issue an error message (with text) */ isDec: return verify( arg(1), 1234567890) \== 0 /*insure argument is just decimal digs.*/ leapYr: arg _; ly=_//4==0; if ly==0 then return 0; ly=((_//100\==0)|_//400==0); return ly serDAT: call err 'illegal date format with a separator= ['sep"], date= " @dat /*──────────────────────────────────────────────────────────────────────────────────────*/ conv: parse arg @dat /*obtain date that the user specified. */
if sep=='-' then parse var @dat yr.a "-" mon.a '-' dd.a /* yy-mm-dd */ if sep=='/' then parse var @dat mon.a "/" dd.a '/' yr.a /* mm/dd/yy */ if sep=='\' then parse var @dat dd.a "\" mon.a '\' yr.a /* dd\mm\yy */ if yr.a== then yr.a= right( date(), 4) /*omitted yy*/ if length(yr.a)==2 then yr.a= left( date('S'), 2)yr.a /*2 dig yy ?*/ if yr.a==. | mon.a==. | dd.a==. then call serDAT /*validate. */ return</lang>
- output when using the inputs of: * 2000-1-1
Today (indicated by the asterisk) is 2019-10-2
7,214 days between 2019-10-02 and 2000-01-01
Ring
<lang ring> load "stdlib.ring"
DaysBetween = [["1995-11-21","1995-11-21"],
["2019-01-01","2019-01-02"], ["2019-01-02","2019-01-01"], ["2019-01-01","2019-03-01"], ["2020-01-01","2020-03-01"], ["1902-01-01","1968-12-25"], ["2090-01-01","2098-12-25"]]
for n = 1 to len(DaysBetween)
date1 = DaysBetween[n][1] date2 = DaysBetween[n][2] date3 = substr(date1,9,2) + "/" + substr(date1,6,2) + "/" + substr(date1,1,4) date4 = substr(date2,9,2) + "/" + substr(date2,6,2) + "/" + substr(date2,1,4) ? "Days between " + DaysBetween[n][1] + " and " + DaysBetween[n][2] + ": " + diffdays(date4,date3)
next </lang>
- Output:
Days between 1995-11-21 and 1995-11-21: 0 Days between 2019-01-01 and 2019-01-02: 1 Days between 2019-01-02 and 2019-01-01: -1 Days between 2019-01-01 and 2019-03-01: 59 Days between 2020-01-01 and 2020-03-01: 60 Days between 1902-01-01 and 1968-12-25: 0 Days between 2090-01-01 and 2098-12-25: 3280
Ruby
<lang ruby>require "date"
d1, d2 = Date.parse("2019-1-1"), Date.parse("2019-10-19")
p (d1 - d2).to_i # => -291 p (d2 - d1).to_i # => 291 </lang>
Rust
<lang rust>// [dependencies] // chrono = "0.4"
use chrono::NaiveDate;
fn main() {
let args: Vec<String> = std::env::args().collect(); if args.len() != 3 { eprintln!("usage: {} start-date end-date", args[0]); std::process::exit(1); } if let Ok(start_date) = NaiveDate::parse_from_str(&args[1], "%F") { if let Ok(end_date) = NaiveDate::parse_from_str(&args[2], "%F") { let d = end_date.signed_duration_since(start_date); println!("{}", d.num_days()); } else { eprintln!("Can't parse end date"); std::process::exit(1); } } else { eprintln!("Can't parse start date"); std::process::exit(1); }
}</lang>
- Output:
days_between_dates 2020-01-01 2020-09-06 249
Scala
<lang scala>object DaysBetweenDates {
/*Inspired by the Python version of the algorithm and the discussion here https://stackoverflow.com/questions/12862226/the-implementation-of-calculating-the-number-of-days-between-2-dates.*/
/**Transform a date into a day number in the Gregorian Calendar*/ def dateToDays(year : Int, month : Int, day : Int ) : Int = { val m = (month+ 9) % 12 val y = year - m/10 val d = day 365*y + y/4 - y/100 + y/400 + (m*306 + 5)/10 + (d - 1) }
/**Compute the difference of days between both input dates*/ def daysDifference(firstDate : String, secondDate : String) : Int = { val firstDateTuple = firstDate.split('-') match { case Array(a, b, c) => (a, b, c) } val secondDateTuple = secondDate.split('-') match { case Array(a, b, c) => (a, b, c) }
val firstYear = dateToDays( firstDateTuple._1.toInt, firstDateTuple._2.toInt, firstDateTuple._3.toInt) val secondYear = dateToDays( secondDateTuple._1.toInt, secondDateTuple._2.toInt, secondDateTuple._3.toInt )
return secondYear - firstYear }
def main(args: Array[String]): Unit = { println(daysDifference("2019-01-01", "2019-09-30")) println(daysDifference("1995-11-21", "1995-11-21")) println(daysDifference("2019-01-01", "2019-01-02")) println(daysDifference("2019-01-02", "2019-01-01")) println(daysDifference("2019-01-01", "2019-03-01")) println(daysDifference("2020-01-01", "2020-03-01")) println(daysDifference("1902-01-01", "1968-12-25")) println(daysDifference("2090-01-01", "2098-12-25")) println(daysDifference("1902-01-01", "2098-12-25")) }
} </lang>
- Output:
272 0 1 -1 59 60 24465 3280 71947
Sidef
<lang ruby>require('Date::Calc')
func days_diff(a,b) {
%S<Date::Calc>.Delta_Days(a.split('-')..., b.split('-')...)
}
var date1 = "1970-01-01" var date2 = "2019-10-02"
say "Date 1: #{date1}" say "Date 2: #{date2}"
var days = days_diff(date1, date2)
say "There are #{days} days between these dates"</lang>
- Output:
Date 1: 1970-01-01 Date 2: 2019-10-02 There are 18171 days between these dates
Swift
<lang swift>import Foundation
func daysFromTimeInterval(_ interval: Double) -> Int {
return Int(interval) / 86400
}
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
print("Enter date one (yyyy-MM-dd): ", terminator: "")
guard let date1Str = readLine(strippingNewline: true), let date1 = formatter.date(from: date1Str) else {
fatalError("Invalid date two")
}
print("Enter date two (yyyy-MM-dd): ", terminator: "")
guard let date2Str = readLine(strippingNewline: true), let date2 = formatter.date(from: date2Str) else {
fatalError("Invalid date two")
}
let (start, end) = date1 > date2 ? (date2, date1) : (date1, date2) let days = daysFromTimeInterval(DateInterval(start: start, end: end).duration)
print("There are \(days) days between \(start) and \(end)")</lang>
- Output:
Enter date one (yyyy-MM-dd): 2019-01-01 Enter date two (yyyy-MM-dd): 2019-12-02 There are 335 days between 2019-01-01 05:00:00 +0000 and 2019-12-02 05:00:00 +0000
UNIX Shell
<lang bash># return true if year is leap in Gregorian calendar leap() {
local -i year year=$1 if (( year % 4 )); then return 1; fi if (( year % 100 )); then return 0; fi ! (( year % 400 ))
}
- convert date to Gregorian day count (Rata Die), where RD 1 = January 1, 1 CE
rd() {
local year month day IFS=- read year month day <<<"$1" local -i elapsed_years=year-1 (( day += elapsed_years * 365 )) (( day += elapsed_years/4 )) (( day -= elapsed_years/100 )) (( day += elapsed_years/400 )) local month_lengths=(31 28 31 30 31 30 31 31 30 31 30 31) if leap "$year"; then let month_lengths[1]+=1; fi local m for (( m=0; m<month-1; ++m)); do (( day += month_lengths[m] )) done printf '%d\n' "$day"
}
days_between() {
local -i date1 date2 date1=$(rd "$1") date2=$(rd "$2") printf '%d\n' $(( date2 - date1 ))
}
days_between 1970-01-01 2019-12-04 </lang>
- Output:
18234
Visual Basic .NET
<lang vbnet>Imports System.Globalization
Module Module1
Function DateDiff(d1 As String, d2 As String) As Integer Dim a = DateTime.ParseExact(d1, "yyyy-MM-dd", CultureInfo.InvariantCulture) Dim b = DateTime.ParseExact(d2, "yyyy-MM-dd", CultureInfo.InvariantCulture) Return (b - a).TotalDays End Function
Sub Main() Console.WriteLine(DateDiff("1970-01-01", "2019-10-18")) End Sub
End Module</lang>
- Output:
18187
Wren
<lang ecmascript>import "/date" for Date
var datePairs = [
["1995-11-21", "1995-11-21"], ["2019-01-01", "2019-01-02"], ["2019-01-02", "2019-01-01"], ["2019-01-01", "2019-03-01"], ["2020-01-01", "2020-03-01"], ["1902-01-01", "1968-12-25"], ["2090-01-01", "2098-12-25"], ["1902-01-01", "2098-12-25"], ["1970-01-01", "2019-10-18"], ["2019-03-29", "2029-03-29"], ["2020-02-29", "2020-03-01"]
] for (dates in datePairs) {
var date1 = Date.parse(dates[0]) var date2 = Date.parse(dates[1]) var days = (date2 - date1).days Date.default = Date.isoDate System.print("Days between %(date1) and %(date2) = %(days)")
}</lang>
- Output:
Days between 1995-11-21 and 1995-11-21 = 0 Days between 2019-01-01 and 2019-01-02 = 1 Days between 2019-01-02 and 2019-01-01 = -1 Days between 2019-01-01 and 2019-03-01 = 59 Days between 2020-01-01 and 2020-03-01 = 60 Days between 1902-01-01 and 1968-12-25 = 24465 Days between 2090-01-01 and 2098-12-25 = 3280 Days between 1902-01-01 and 2098-12-25 = 71947 Days between 1970-01-01 and 2019-10-18 = 18187 Days between 2019-03-29 and 2029-03-29 = 3653 Days between 2020-02-29 and 2020-03-01 = 1
zkl
<lang zkl>var [const] TD=Time.Date; today:=TD.parseDate("--"); // "yyyy-mm-dd" and variations --> (y,m,d) // or Time.Clock.UTC --> (y,m,d,h,m,s) then:=TD.parseDate("2018-9-30"); diff:=TD.deltaDays(then,today.xplode()); // ( (y,m,d), y,m,d ) println("Number of days between %s and %s: %d".fmt(then,today,diff)); println("Number of days between %s and %s: %d".fmt(
TD.toYMDString(today.xplode()), // to(y,m,d) not to((y,m,d)) TD.toYMDString(then.xplode()), TD.deltaDays(today,then.xplode())));</lang>
- Output:
Number of days between L(2018,9,30) and L(2019,9,30): 365 Number of days between 2019-09-30 and 2018-09-30: -365