Days between dates: Difference between revisions
no edit summary
(→{{header|Vlang}}: Rename "Vlang" in "V (Vlang)") |
No edit summary |
||
(14 intermediate revisions by 8 users not shown) | |||
Line 179:
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</pre>
=={{header|ALGOL 68}}==
{{Trans|FreeBASIC}}
<syntaxhighlight lang="algol68">
BEGIN # calculate the number of days between a pair of dates #
# based on a translation of the FreeBASIC sample #
[,]STRING test cases
= ( ( "1902-01-01", "1968-12-25" )
, ( "2019-01-01", "2019-01-02" ), ( "2019-01-02", "2019-01-01" )
, ( "2019-01-01", "2019-03-01" ), ( "2020-01-01", "2020-03-01" )
, ( "1995-11-21", "1995-11-21" ), ( "2090-01-01", "2098-12-25" )
);
PROC gregorian = ( INT y, m, d )INT:
BEGIN
INT n = ( m + 9 ) - ( ( ( m + 9 ) OVER 12 ) * 12 );
INT w = y - ( n OVER 10 );
( 365 * w ) + ( w OVER 4 ) - ( w OVER 100 ) + ( w OVER 400 )
+ ( ( ( n * 306 ) + 5 ) OVER 10 ) + ( d - 1 )
END # gregorian # ;
OP TOINT = ( STRING s )INT:
BEGIN
INT v := 0;
FOR s pos FROM LWB s TO UPB s DO
v *:= 10 +:= ( ABS s[ s pos ] - ABS "0" )
OD;
v
END # TOINT #;
FOR n FROM LWB test cases TO UPB test cases DO
STRING from date = test cases[ n, 1 ];
STRING to date = test cases[ n, 2 ];
INT from g = gregorian( TOINT from date[ 1 : 4 ]
, TOINT from date[ 6 : 7 ]
, TOINT from date[ 9 : 10 ]
);
INT to g = gregorian( TOINT to date[ 1 : 4 ]
, TOINT to date[ 6 : 7 ]
, TOINT to date[ 9 : 10 ]
);
print( ( "Days between ", from date, " and ", to date, " is " ) );
print( ( whole( to g - from g, -5 ), " days", newline ) )
OD
END
</syntaxhighlight>
{{out}}
<pre>
Days between 1902-01-01 and 1968-12-25 is 24465 days
Days between 2019-01-01 and 2019-01-02 is 1 days
Days between 2019-01-02 and 2019-01-01 is -1 days
Days between 2019-01-01 and 2019-03-01 is 59 days
Days between 2020-01-01 and 2020-03-01 is 60 days
Days between 1995-11-21 and 1995-11-21 is 0 days
Days between 2090-01-01 and 2098-12-25 is 3280 days
</pre>
=={{header|ALGOL W}}==
{{Trans|FreeBASIC}}
<syntaxhighlight lang="algolw">
begin % calculate the number of days between a pair of dates %
% based on a translation of the FreeBASIC sample %
integer procedure gregorian ( integer value y, m, d ) ;
begin
integer n, w;
n := ( m + 9 ) - ( ( ( m + 9 ) div 12 ) * 12 );
w := y - ( n div 10 );
( 365 * w ) + ( w div 4 ) - ( w div 100 ) + ( w div 400 )
+ ( ( ( n * 306 ) + 5 ) div 10 ) + ( d - 1 )
end gregorian ;
integer procedure toInt( string(4) value s ) ;
begin
integer v;
v := 0;
for sPos := 0 until 3 do begin
string(1) c;
c := s( sPos // 1 );
if c not = " " then v := ( v * 10 ) + ( decode( c ) - decode( "0" ) )
end;
v
end toInt ;
procedure testGregorian ( string(10) value fromDate, toDate ) ;
begin
integer fromG, toG;
fromG := gregorian( toInt( fromDate( 0 // 4 ) )
, toInt( fromDate( 5 // 2 ) )
, toInt( fromDate( 8 // 2 ) )
);
toG := gregorian( toInt( toDate( 0 // 4 ) )
, toInt( toDate( 5 // 2 ) )
, toInt( toDate( 8 // 2 ) )
);
writeon( s_w := 0, "Days between ", fromDate, " and ", toDate, " is " );
writeon( i_w := 5, s_w := 0, toG - fromG, " days" );
write();
end testGregorian ;
testGregorian( "1902-01-01", "1968-12-25" );testGregorian( "2019-01-01", "2019-01-02" );
testGregorian( "2019-01-02", "2019-01-01" );testGregorian( "2019-01-01", "2019-03-01" );
testGregorian( "2020-01-01", "2020-03-01" );testGregorian( "1995-11-21", "1995-11-21" );
testGregorian( "2090-01-01", "2098-12-25" )
end.
</syntaxhighlight>
{{out}}
<pre>
Days between 1902-01-01 and 1968-12-25 is 24465 days
Days between 2019-01-01 and 2019-01-02 is 1 days
Days between 2019-01-02 and 2019-01-01 is -1 days
Days between 2019-01-01 and 2019-03-01 is 59 days
Days between 2020-01-01 and 2020-03-01 is 60 days
Days between 1995-11-21 and 1995-11-21 is 0 days
Days between 2090-01-01 and 2098-12-25 is 3280 days
</pre>
=={{header|AppleScript}}==
Line 1,130 ⟶ 1,248:
Days between 2090-01-01 and 2098-12-25 is 3280 days
</pre>
=={{header|Frink}}==
Line 1,149 ⟶ 1,266:
=={{header|Fōrmulæ}}==
{{FormulaeEntry|page=https://formulae.org/?timeZone=America%2FLos_Angeles&script=examples/Days_between_dates}}
'''Solution'''
Note. For this script, the time zone is intentionally set to America/Los_Angeles, because it observes [https://en.wikipedia.org/wiki/Daylight_saving_time daylight saving time], It is necesary to solve this exercise.
Provided that the ToNumber expression applied to a time expression reduces to the number of milliseconds of such that time from the [https://en.wikipedia.org/wiki/Epoch_(computing) epoch]:
[[File:Fōrmulæ - Days between dates 01.png]]
[[File:Fōrmulæ - Days between dates 02.png]]
The solution seems easy, calculating the difference between two times (in milliseconds), and dividing by 86,4000,000 (number of milliseconds in a day):
[[File:Fōrmulæ - Days between dates 03.png]]
[[File:Fōrmulæ - Days between dates 04.png]]
However, it does not work if one time is in daylight saving time, and the other one is in standard time:
[[File:Fōrmulæ - Days between dates 05.png]]
[[File:Fōrmulæ - Days between dates 06.png]]
[[File:Fōrmulæ - Days between dates 07.png]]
[[File:Fōrmulæ - Days between dates 08.png]]
'''Solution 1'''
The first solution consists in simply rounding the result to the nearest integer:
[[File:Fōrmulæ - Days between dates 09.png]]
[[File:Fōrmulæ - Days between dates 10.png]]
'''Solution 2'''
The expression GetTimeZoneOffset reduces to the offset (in minutes) of the given time.
[[File:Fōrmulæ - Days between dates 11.png]]
[[File:Fōrmulæ - Days between dates 12.png]]
[[File:Fōrmulæ - Days between dates 13.png]]
[[File:Fōrmulæ - Days between dates 14.png]]
The solution consist in taking this difference in account.
So, the function that works correctly is:
[[File:Fōrmulæ - Days between dates 15.png]]
'''Test cases'''
[[File:Fōrmulæ - Days between dates 16.png]]
[[File:Fōrmulæ - Days between dates 17.png]]
Notice that it works even for fractions of days:
[[File:Fōrmulæ - Days between dates 18.png]]
[[File:Fōrmulæ - Days between dates 19.png]]
=={{header|Go}}==
Line 1,492 ⟶ 1,669:
Enter date 2: 2019-10-02
There are 18171 days between these dates.</pre>
=={{header|M2000 Interpreter}}==
Version 12 has date type, so we can handle easy dates.
<syntaxhighlight lang="m2000 interpreter">
module Days_between_dates{
date a="2019-01-01", b="2019-09-30"
long z=b-a
// Use the system default to display dates (DD/MM/YYYY)
Print "Days from "+a+" to "+b+" = "+z
// using locale 1033 to display dates (MM/DD/YYYY)
Print "Days from "+date$(a, 1033)+" to "+date$(b, 1033)+" = "+z
}
Days_between_dates
</syntaxhighlight>
{{out}}
<pre>
Days from 1/1/2019 to 30/9/2019 = 272
Days from 1/1/2019 to 9/30/2019 = 272
</pre>
=={{header|Mathematica}} / {{header|Wolfram Language}}==
Line 1,526 ⟶ 1,724:
Days between 1902-01-01 and 1968-12-25: 24465
Days between 2090-01-01 and 2098-12-25: 3280</pre>
=={{header|Pascal}}==
==={{header|Free Pascal}}===
<syntaxhighlight lang="pascal">
Program DaysBetweenDates;
{$mode ObjFPC}{$H+}
Uses dateutils,strutils;
Type Tarr = array of array Of string;
Const lst : Tarr = (('1902-01-01','1968-12-25'),('2019-01-01','2019-01-02'),
('2019-01-02','2019-01-01'),('2019-01-01','2019-03-01'),
('2020-01-01','2020-03-01'),('1995-11-21','1995-11-21'),
('2090-01-01','2098-12-25'),('1967-02-23','2024-03-21'));
Function strtodate(str : String) : tdatetime;
Begin
result := ScanDateTime('YYYYMMDD', DelChars(str, '-'));
End;
Var arr : array of string;
DaysBetw : integer;
Begin
For arr In lst Do
Begin
DaysBetw := DaysBetween(strtodate(arr[0]),strtodate(arr[1]));
writeln(arr[0],' - ',arr[1],' -> ',DaysBetw);
End;
End.
</syntaxhighlight>
{{out}}
<pre>
1902-01-01 - 1968-12-25 -> 24465
2019-01-01 - 2019-01-02 -> 1
2019-01-02 - 2019-01-01 -> 1
2019-01-01 - 2019-03-01 -> 59
2020-01-01 - 2020-03-01 -> 60
1995-11-21 - 1995-11-21 -> 0
2090-01-01 - 2098-12-25 -> 3280
1967-02-23 - 2024-03-21 -> 20846
</pre>
=={{header|Perl}}==
Line 1,595 ⟶ 1,835:
</pre>
=={{header|PL/I-80}}==
{{Trans|S-BASIC}}
<syntaxhighlight lang = "PL/I">
elapsed_days: proc options (main);
dcl
(date1, date2) float bin,
another char(1);
put skip list ('Elapsed days calculator');
another = 'Y';
do while ((another = 'Y') | (another = 'y'));
put skip list ('First date as YYYY-MM-DD : ');
date1 = get_date();
put list ('Second date as YYYY-MM-DD : ');
date2 = get_date();
put skip edit ('Elapsed days = ', date2-date1) (a,f(6));
put skip list ('Do another (y/n)? ');
get edit (another) (a);
end;
/*
* Read a date in YYYY-MM-DD format from the
* console and return its serial date equivalent
*/
get_date: proc returns (float bin);
dcl date char(20) varying;
dcl (y, m, d) float bin;
get edit (date) (a);
y = binary(substr(date,1,4));
m = binary(substr(date,6,2));
d = binary(substr(date,9,2));
return (serial_date(y,m,d));
end get_date;
/*
* Given a year, month and day in the Gregorian
* calendar, return a numeric date which is equal
* to the number of days since the start of the
* Common era
*/
serial_date: proc (yr, mo, da) returns (float bin);
dcl (yr, mo, da) float bin;
dcl n float bin;
n = 365 * yr + da + 31 * (mo - 1);
if (mo >= 3) then
n = n - fixed(0.4 * mo + 2.3);
else
yr = yr - 1;
n = n + fixed(yr/4) - fixed(0.75 * fixed(yr/100) + 1);
return (n);
end serial_date;
end elapsed_days;
</syntaxhighlight>
{{out}}
Test case taken from the Delphi example
<pre>
Elapsed Date Calculator
First date as YYYY-MM-DD : 1970-01-01
Second date as YYYY-MM-DD : 2019-10-18
Elapsed days = 18187
Do another (y/n)? n
</pre>
=={{header|PL/M}}==
{{Trans|FreeBASIC}}
{{works with|8080 PL/M Compiler}} ... under CP/M (or an emulator)<br>
Note that as the 8080 PL/M compiler only supports 8 and 16 bit unsigned integers, the dates must be at most 65535 days apart.
<syntaxhighlight lang="plm">
100H: /* CALCULATE THE NUMBER OF DAYS BETWEEN TWO DATES; BASED ON FREEBASIC */
/* CP/M BDOS SYSTEM CALL AND I/O ROUTINES */
BDOS: PROCEDURE( FN, ARG ); DECLARE FN BYTE, ARG ADDRESS; GOTO 5; END;
PR$CHAR: PROCEDURE( C ); DECLARE C BYTE; CALL BDOS( 2, C ); END;
PR$STRING: PROCEDURE( S ); DECLARE S ADDRESS; CALL BDOS( 9, S ); END;
PR$NL: PROCEDURE; CALL PR$CHAR( 0DH ); CALL PR$CHAR( 0AH ); END;
PR$NUMBER: PROCEDURE( N ); /* PRINTS A NUMBER IN THE MINIMUN FIELD WIDTH */
DECLARE N ADDRESS;
DECLARE V ADDRESS, N$STR ( 6 )BYTE, W BYTE;
V = N;
W = LAST( N$STR );
N$STR( W ) = '$';
N$STR( W := W - 1 ) = '0' + ( V MOD 10 );
DO WHILE( ( V := V / 10 ) > 0 );
N$STR( W := W - 1 ) = '0' + ( V MOD 10 );
END;
CALL PR$STRING( .N$STR( W ) );
END PR$NUMBER;
PR$SIGNED: PROCEDURE( N ); /* PRINTS N AS A SIGNED INTEGER */
DECLARE N ADDRESS;
IF N <= 32767
THEN CALL PR$NUMBER( N );
ELSE DO;
CALL PR$CHAR( '-' );
CALL PR$NUMBER( - N );
END;
END PR$SIGNED ;
/* TASK */
/* RETURNS THE GREGORIAN DAY CORRESPONDING TO YYYY/MM/DD */
GREGORIAN: PROCEDURE( YYYY$MM$DD )ADDRESS;
DECLARE YYYY$MM$DD ADDRESS;
DECLARE DATE BASED YYYY$MM$DD ( 10 )BYTE;
DECLARE ( YYYY, MM, DD, N, W ) ADDRESS;
DIGIT: PROCEDURE( D )BYTE; DECLARE D BYTE; RETURN D - '0'; END;
YYYY = ( DIGIT( DATE( 0 ) ) * 1000 ) + ( DIGIT( DATE( 1 ) ) * 100 )
+ ( DIGIT( DATE( 2 ) ) * 10 ) + DIGIT( DATE( 3 ) );
MM = ( DIGIT( DATE( 5 ) ) * 10 ) + DIGIT( DATE( 6 ) );
DD = ( DIGIT( DATE( 8 ) ) * 10 ) + DIGIT( DATE( 9 ) );
N = ( MM + 9 ) - ( ( ( MM + 9 ) / 12 ) * 12 );
W = YYYY - ( N / 10 );
RETURN ( 365 * W ) + ( W / 4 ) - ( W / 100 ) + ( W / 400 )
+ ( ( ( N * 306 ) + 5 ) / 10 ) + ( DD - 1 );
END GREGORIAN ;
/* SHOWS TTHE DAYS DIFFERENCE BETWEEN FROM$G AND TO$$G */
PR$DAYS$DIFFERENCE: PROCEDURE( FROM$DATE, TO$DATE );
DECLARE ( FROM$DATE, TO$DATE )ADDRESS;
CALL PR$STRING( .'DAYS BETWEEN $' );CALL PR$STRING( FROM$DATE );
CALL PR$STRING( .' AND $' );CALL PR$STRING( TO$DATE );
CALL PR$STRING( .' IS $' );
CALL PR$SIGNED( GREGORIAN( TO$DATE ) - GREGORIAN( FROM$DATE ) );
CALL PR$NL;
END PR$DAYS$DIFFERENCE ;
CALL PR$DAYS$DIFFERENCE( .'1902-01-01$', .'1968-12-25$' );
CALL PR$DAYS$DIFFERENCE( .'2019-01-01$', .'2019-01-02$' );
CALL PR$DAYS$DIFFERENCE( .'2019-01-02$', .'2019-01-01$' );
CALL PR$DAYS$DIFFERENCE( .'2019-01-01$', .'2019-03-01$' );
CALL PR$DAYS$DIFFERENCE( .'2020-01-01$', .'2020-03-01$' );
CALL PR$DAYS$DIFFERENCE( .'1995-11-21$', .'1995-11-21$' );
CALL PR$DAYS$DIFFERENCE( .'2090-01-01$', .'2098-12-25$' );
EOF
</syntaxhighlight>
{{out}}
<pre>
DAYS BETWEEN 1902-01-01 AND 1968-12-25 IS 24465
DAYS BETWEEN 2019-01-01 AND 2019-01-02 IS 1
DAYS BETWEEN 2019-01-02 AND 2019-01-01 IS -1
DAYS BETWEEN 2019-01-01 AND 2019-03-01 IS 59
DAYS BETWEEN 2020-01-01 AND 2020-03-01 IS 60
DAYS BETWEEN 1995-11-21 AND 1995-11-21 IS 0
DAYS BETWEEN 2090-01-01 AND 2098-12-25 IS 3280
</pre>
=={{header|Python}}==
Line 1,861 ⟶ 2,249:
Days between 1902-01-01 and 1968-12-25: 0
Days between 2090-01-01 and 2098-12-25: 3280
</pre>
=={{header|RPL}}==
Uses Python formula, in a forced binary calculation mode to avoid 'flooring' instructions
{{works with|Halcyon Calc|4.2.7}}
≪ → d m y
≪ m 9 + 12 MOD
y OVER #10d / -
DUP 365 * OVER #4d / + OVER #100d / - SWAP #400d / +
SWAP 306 * 5 + #10d / + d + 1 - B→R
≫ ≫
'GREGN' STO
≪ SWAP 1 2 '''START'''
→ date
≪ date 9 10 SUB STR→ date 6 7 SUB STR→ date 1 4 SUB STR→
GREGN SWAP
≫
'''NEXT''' -
≫
'NBDAYS' STO
"1902-01-01" "1968-12-25" NBDAYS
"2019-01-02" "2019-01-01" NBDAYS
"2019-01-01" "2019-03-01" NBDAYS
"2020-01-01" "2020-03-01" NBDAYS
{{out}}
<pre>
4: 24465
3: -1
2: 59
1: 60
</pre>
Line 1,902 ⟶ 2,322:
days_between_dates 2020-01-01 2020-09-06
249
</pre>
=={{header|S-BASIC}}==
Error checking of entered dates is omitted in order to focus
on the stated task but would obviously have to be included
in production code.
<syntaxhighlight lang = "BASIC">
comment
Given a month, day, and year in the Gregorian calendar,
return a numeric date which is equal to the number of
days since the start of the Common era.
end
function serial_date(da, mo, yr = integer) = real
var n = real
n = 365 * yr + da + 31 * (mo - 1)
if mo >= 3 then
n = n - int(.4 * mo + 2.3)
else
yr = yr - 1
n = n + int(yr/4) - int(.75 * (int(yr/100) + 1))
end = n
comment
Read a date in YYYY-MM-DD format from the console and
return its serial date equivalent.
end
function get_date = real
var date = string : 20
var y, m, d = integer
input2 date
y = val(mid(date,1,4))
m = val(mid(date,6,2))
d = val(mid(date,9,2))
end = serial_date(d, m, y)
rem -- main program begins here
var date1, date2 = real
var another = char
repeat
begin
print "First date : ";
date1 = get_date
print "Second date : ";
date2 = get_date
print "Elapsed days = "; date2 - date1
input "Do another (y/n)"; another
end
until not another
end
</syntaxhighlight>
{{out}}
Test dates taken from Delphi example
<pre>
First date : 1970-01-01
Second date : 2019-10-18
Elapsed days = 18187
Do another (y/n)? n
</pre>
Line 2,115 ⟶ 2,595:
=={{header|Wren}}==
{{libheader|Wren-date}}
<syntaxhighlight lang="
var datePairs = [
Line 2,130 ⟶ 2,610:
["2020-02-29", "2020-03-01"]
]
Date.default = Date.isoDate
for (dates in datePairs) {
var date1 = Date.parse(dates[0])
var date2 = Date.parse(dates[1])
var days = (date2 - date1).days
System.print("Days between %(date1) and %(date2) = %(days)")
}</syntaxhighlight>
Line 2,151 ⟶ 2,631:
Days between 2019-03-29 and 2029-03-29 = 3653
Days between 2020-02-29 and 2020-03-01 = 1
</pre>
=={{header|XPL0}}==
{{trans|FreeBASIC}}
<syntaxhighlight lang "XPL0">func Gregorian(Y, M, D); \Return Gregorian day given date
int Y, M, D;
int N, W;
[N:= M + 9 - (M+9)/12*12;
W:= Y - N/10;
return 365*W + W/4 - W/100 + W/400 + (N*306+5)/10 + D - 1;
];
int Dates, N, Y, M, D, G0, G1;
[Dates:= [
["2019-01-01", "2019-01-02"],
["2019-01-02", "2019-01-01"],
["2019-01-01", "2019-03-01"],
["2020-01-01", "2020-03-01"],
["1995-11-21", "1995-11-21"],
["2090-01-01", "2098-12-25"] ];
OpenO(8); OpenI(8);
for N:= 0 to 6-1 do
[Text(8, Dates(N,0));
Y:= IntIn(8); M:= IntIn(8); D:= IntIn(8);
G0:= Gregorian(Y, M, D);
Text(8, Dates(N,1));
Y:= IntIn(8); M:= IntIn(8); D:= IntIn(8);
G1:= Gregorian(Y, M, D);
Text(0, "Number of days between "); Text(0, Dates(N,0)); Text(0, " and ");
Text(0, Dates(N,1)); Text(0, " is "); IntOut(0, abs(G1-G0)); CrLf(0);
];
]</syntaxhighlight>
{{out}}
<pre>
Number of days between 2019-01-01 and 2019-01-02 is 1
Number of days between 2019-01-02 and 2019-01-01 is 1
Number of days between 2019-01-01 and 2019-03-01 is 59
Number of days between 2020-01-01 and 2020-03-01 is 60
Number of days between 1995-11-21 and 1995-11-21 is 0
Number of days between 2090-01-01 and 2098-12-25 is 3280
</pre>
|