Time to Days, hours, minutes and seconds

Previous topic - Next topic

MrTAToad

QuoteWill see what output I get on my home machine this weekend as that has Delphi installed as well as Free Pascal on Linux & will enter the same dates you tried.
That'll be good - if they differ, then there is a mathematical problem somewhere.  Its possible that some extra leap years were being taken into account too...

I've produced this, which uses a different calculation for things, and is based on this site http://www.onlineconversion.com/julian_date.htm

Download : http://dl.dropbox.com/u/25216439/Test2.app.rar

[attachment deleted by admin]

Kitty Hello

Wow, that's very handy. Now I only need a few days off to make some notes on this. ;)

fuzzy70

I have found out why the code gave incorrect results on pre 1585 dates, just a pure simple typo.

The original code in the Pascal version of the MJD function was

THEN B:=-2+TRUNC((YEAR+4716)/4)-1179


The converted was

b=2+INTEGER((year%+4716)/4)-1179

I have underlined & made bold the difference, Just a simple "-" sign was missing & a very easy mistake to make thanks to := being used in Pascal. Here is the amended version & I have tested it on the dates you had problems with & they return the correct values back

Code (glbasic) Select
LOCAL day%,month%,year%,hour%

DEBUG MJD(24,5,1500,12)+"\n"
CALDAT(-130923.5,day%,month%,year%,hour%)
DEBUG day%+" "+month%+" "+year%+" "+hour%

FUNCTION MJD:day%,month%,year%,hour
LOCAL a,b%

a=10000.0*year%+100.0*month%+day%
IF month%<=2
INC month%,12
DEC year%
ENDIF

IF a<=15821004.1
b=-2+INTEGER((year%+4716)/4)-1179
ELSE
b=INTEGER(year%/400)-INTEGER(year%/100)+INTEGER(year%/4)
ENDIF

a=365.0*year%-679004.0
RETURN a+b+INTEGER(30.6001*(month%+1))+day%+hour/24.0
ENDFUNCTION

FUNCTION CALDAT%:value,BYREF day%,BYREF month%,BYREF year%,BYREF hour%
LOCAL b%,d%,f%
LOCAL jd,jd0,c,e

jd=value+2400000.5
jd0=INTEGER(jd+0.5)
IF jd0<2299161.0
c=jd0+1524.0
ELSE
b%=INTEGER((jd0-1867216.25)/36524.25)
c=jd0+(b-INTEGER(b%/4))+1525.0
ENDIF

d%=INTEGER((c-122.1)/365.25); e=365.0*d+INTEGER(d%/4)
f%=INTEGER((c-e)/30.6001)
day%=INTEGER(c-e+0.5)-INTEGER(30.6001*f%); month%=f%-1-12*INTEGER(f%/14)
year%=d%-4715-INTEGER((7+month%)/10); hour%=24.0*(jd+0.5-jd0)
ENDFUNCTION


Lee
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

MrTAToad


MrTAToad

#19
I'm incorporating both versions into the program now :)

Your version does seem to be an out by hour though :

Code (glbasic) Select

DEBUG MJD(24,5,2012,17)+"\n"
CALDAT(56071.70833,day%,month%,year%,hour%)
DEBUG day%+" "+month%+" "+year%+" "+hour%
END


Gives :

56071.70833
24 5 2012 16

fuzzy70

Interesting, seems to happen on any hour >=14 regardless of year etc. Time for some investigation me thinks ;)

Lee

Sent from my GT-I5700 using Tapatalk 2
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

MrTAToad

#21
I've got a nasty feeling its a rounding problem.

For example, hour ends up being 16.992, which would mean when converted to an integer would come out at as 16...

This code modification seems to work out okay though :

Code (glbasic) Select
hour%=(24.0*(jd+0.5-jd0))+0.05

fuzzy70

It is indeed a rounding problem. Using the one prior to your 0.05 I done it by hand & the 17 hour / 24 is 0.7083333333 recurring. Adding the extra 3's returned the correct answer.

Lee

Sent from my GT-I5700 using Tapatalk 2
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

Ian Price

You lot obviously have too much time on your hands... ;) :P
I came. I saw. I played.

erico

Ok, so when do we test the code on the Delorian? :P

Slydog

Quote from: erico on 2012-May-24
Ok, so when do we test the code on the Delorian? :P

When we can get our FPS up to 88!
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

MrTAToad

I've finished my conversion program.  It generally works well, but does occasionally suffer from occasional rounding errors.  Usually it's only out by a second, but occasionally I have seen it out by a day.

Download : http://dl.dropbox.com/u/25216439/DateToJulian.app.rar

[attachment deleted by admin]

erico

 :D :good:


[attachment deleted by admin]

MrTAToad

Heh  :good:

Here is the code for the program :

Code (glbasic) Select
GLOBAL gDDguiMinControlDimension%=16

LOCAL day%,month%,year%,hour%
LOCAL sW%=320,sH%=240
LOCAL size%,temp$,v
LOCAL dateTime$[],date$[],time$[]

size%=(sW%/6)-8

DIM dateTime$[0]
IF SPLITSTR(PLATFORMINFO$("TIME"),dateTime$[]," ")>=2
// Get the date
DIM date$[0]
DIM time$[0]

IF SPLITSTR(dateTime$[0],date$[],"-")<>3 OR SPLITSTR(dateTime$[1],time$[],":")<>3
DDgui_msg("Date/Time split is invalid",FALSE,"* Error *")
RETURN FALSE
ENDIF
ELSE
DDgui_msg("Can't get current date and time",FALSE,"* Error *")
RETURN FALSE
ENDIF

LOADFONT "Media/smalfont.png",0
SETFONT 0

DDgui_pushdialog(0,0,sW%,sH%)
DDgui_tab("tab","Julian To Value,f1,type1,wday1,day1,wmonth1,month1,wyear1,year1,whour1,hour1,wmin1,min1,wsec1,sec1,convert1,wresult|"+ _
"Value To Julian,f2,value,type2,convert2,wday2,day2,wmonth2,month2,wyear2,year2,whour2,hour2,wmin2,min2,wsec2,sec2")
DDgui_framestart("f1","Enter Julian Date",sW%-8)
DDgui_checkbox("usnavy1"," Use US Navy Routine",sW%-8,0)
DDgui_radio("type1","AD|BC",sW%-8);
DDgui_widget("wday1","Day",size%,0); DDgui_numbertext("day1",date$[2],size%)
DDgui_widget("wmonth1"," Mnth",size%,0); DDgui_numbertext("month1",date$[1],size%)
DDgui_widget("wyear1"," Year",size%,0); DDgui_numbertext("year1",date$[0],size%)
DDgui_widget("whour1"," Hour",size%,0); DDgui_numbertext("hour1",time$[0],size%)
DDgui_widget("wmin1"," Min",size%,0); DDgui_numbertext("min1",time$[1],size%)
DDgui_widget("wsec1"," Sec",size%,0); DDgui_numbertext("sec1",time$[2],size%)
DDgui_button("convert1","Convert To Modified Julian Date value",sW%-18,0)
DDgui_widget("wresult","Resulting date value :",0,0); DDgui_numbertext("result1","",128); DDgui_set("result1","READONLY",TRUE)
DDgui_frameend()

DDgui_framestart("f2","Enter Modified Julian Date value",sW%-8)
DDgui_numbertext("value","",sW%-18)
DDgui_checkbox("usnavy2"," Use US Navy Routine",sW%-8,0)
DDgui_button("convert2","Convert To Standard calendar Format",sW%-18,0)
DDgui_radio("type2","AD|BC",sW%-8); //DDgui_set("type2","READONLY",TRUE)
DDgui_widget("wday2","Day",size%,0); DDgui_numbertext("day2","",size%); DDgui_set("day2","READONLY",TRUE)
DDgui_widget("wmonth2"," Mnth",size%,0); DDgui_numbertext("month2","",size%); DDgui_set("month2","READONLY",TRUE)
DDgui_widget("wyear2"," Year",size%,0); DDgui_numbertext("year2","",size%); DDgui_set("year2","READONLY",TRUE)
DDgui_widget("whour2"," Hour",size%,0); DDgui_numbertext("hour2","",size%); DDgui_set("hour2","READONLY",TRUE)
DDgui_widget("wmin2"," Min",size%,0); DDgui_numbertext("min2","",size%); DDgui_set("min2","READONLY",TRUE)
DDgui_widget("wsec2"," Sec",size%,0); DDgui_numbertext("sec2","",size%); DDgui_set("sec2","READONLY",TRUE)
DDgui_frameend()

WHILE TRUE
DDgui_show(FALSE)
SHOWSCREEN

IF DDgui_get("usnavy1","CLICKED")
IF INTEGER(DDgui_get("usnavy1","SELECT"))
// US Navy needs access to AD/BC and mins and secs
DDgui_set("type1","READONLY",FALSE)
DDgui_set("min1","READONLY",FALSE)
DDgui_set("sec1","READONLY",FALSE)
ELSE
// Fuzzy 70 doesn't use AC/BC or mins or secs
DDgui_set("type1","READONLY",TRUE)
DDgui_set("min1","READONLY",TRUE)
DDgui_set("sec1","READONLY",TRUE)
DEBUG "Here2\n"
ENDIF
ELSEIF DDgui_get("convert1","CLICKED")
LOCAL day%,month%,year%,hour%,mins%,sec%,isBC%

year%=INTEGER(DDgui_get("year1","TEXT"))
IF year%=0
DDgui_msg("There is no year 0 !",FALSE,"* Error *")
ELSE
day%=INTEGER(DDgui_get("day1","TEXT"))
month%=INTEGER(DDgui_get("month1","TEXT"))
hour%=INTEGER(DDgui_get("hour1","TEXT"))
mins%=INTEGER(DDgui_get("min1","TEXT"))
sec%=INTEGER(DDgui_get("sec1","TEXT"))

IF INTEGER(DDgui_get("usnavy1","SELECT"))
IF INTEGER(DDgui_get("type1","SELECT"))=0
isBC%=FALSE
IF year%=1582 AND month%=10 AND (day%>4 AND day%<15)
DDgui_msg("Error 5/10/1582 to 14/10/1582",FALSE,"* Error *")
CONTINUE
ENDIF
ELSE
isBC%=TRUE
ENDIF

DDgui_set("result1","TEXT",cal_to_jd$(isBC%,year%,month%,day%,hour%,mins%,sec%))
ELSE
IF year%=1582 AND month%=10 AND (day%>4 AND day%<15)
DDgui_msg("Error 5/10/1582 to 14/10/1582",FALSE,"* Error *")
ELSE
DDgui_set("result1","TEXT",MJD(day%,month%,year%,hour%))
ENDIF
ENDIF
ENDIF
ELSEIF DDgui_get("convert2","CLICKED")
LOCAL value$,day%,month%,year%,hour%,mins%,sec%,result%

value$=DDgui_get$("value","TEXT")
IF value$=""
DDgui_msg("No date value entered",FALSE,"* Error *")
ELSE
IF INTEGER(DDgui_get("usnavy2","SELECT"))
result%=jd_to_cal(value$,day%,month%,year%,hour%,mins%,sec%)
IF result%=TRUE
DDgui_set("type2","SELECT",1)
ELSE
DDgui_set("type2","SELECT",0)
ENDIF

DDgui_set("min2","TEXT",RIGHT$("00"+mins%,2))
DDgui_set("sec2","TEXT",RIGHT$("00"+sec%,2))
ELSE
IF CALDAT(value$,day%,month%,year%,hour%)=TRUE
DDgui_set("type2","SELECT",0)
ELSE
DDgui_set("type2","SELECT",1)
ENDIF

DDgui_set("min2","TEXT","N/A")
DDgui_set("sec2","TEXT","N/A")
ENDIF

DDgui_set("day2","TEXT",RIGHT$("00"+day%,2))
DDgui_set("month2","TEXT",RIGHT$("00"+month%,2))
DDgui_set("year2","TEXT",year%)
DDgui_set("hour2","TEXT",RIGHT$("00"+hour%,2))
ENDIF
ENDIF
WEND

FUNCTION MJD:day%,month%,year%,hour
LOCAL a,b%

a=10000.0*year%+100.0*month%+day%
IF month%<=2
INC month%,12
DEC year%
ENDIF

IF a<=15821004.1
b%=-2+INTEGER((year%+4716)/4)-1179
ELSE
b%=INTEGER(year%/400)-INTEGER(year%/100)+INTEGER(year%/4)
ENDIF

a=365.0*year%-679004.0
RETURN a+b%+INTEGER(30.6001*(month%+1))+day%+hour/24.0
ENDFUNCTION

FUNCTION CALDAT%:value,BYREF day%,BYREF month%,BYREF year%,BYREF hour%
LOCAL b%,d%,f%
LOCAL jd,jd0,c,e,r%

jd=value+2400000.5
jd0=INTEGER(jd+0.5)
IF jd0<2299161.0
c=jd0+1524.0
ELSE
b%=INTEGER((jd0-1867216.25)/36524.25)
c=jd0+(b-INTEGER(b%/4))+1525.0
ENDIF

d%=INTEGER((c-122.1)/365.25); e=365.0*d%+INTEGER(d%/4)
f%=INTEGER((c-e)/30.6001)
day%=INTEGER(c-e+0.5)-INTEGER(30.6001*f%); month%=f%-1-12*INTEGER(f%/14)
year%=d%-4715-INTEGER((7+month%)/10); hour%=INTEGER((24.0*(jd+0.5-jd0))+0.005)

IF year%<0
year%=-year%
r%=FALSE
ELSE
r%=TRUE
ENDIF

RETURN r%
ENDFUNCTION

INLINE
extern "C" double floor (      double x );
ENDINLINE

FUNCTION cal_to_jd$:isBC%, y%, m%, d%, h%, mn%, s%
INLINE
long jy,ja,jm,gregcal=15 + 31*( 10 + 12*1582);
double dayfrac,frac,jd0,jd,intgr;

if (isBC)
{
    y = -y + 1;
    }

if (m > 2)
{
jy = y;
jm = m + 1;
}
else
{
jy = y - 1;
jm = m + 13;
}

intgr=floor((365.25*jy)+(30.6001*jm)+d+1720995);

//check for switch to Gregorian calendar
if (d + 31*(m + 12*y) >= gregcal)
{
ja = floor(0.01*jy);
intgr+=2 - ja + floor(0.25*ja);
}

//correct for half-day offset
dayfrac = h/24.0 - 0.5;
if (dayfrac < 0.0)
{
dayfrac++;
intgr--;
}

//now set the fraction of a day
frac = dayfrac + (mn + s/60.0)/60.0/24.0;
    //round to nearest second
    jd0 = (intgr + frac)*100000.0;
    DEBUG("Here : "); DEBUG(DGInt(jd0)); DEBUG("\n");

    jd  = floor(jd0);
    if (jd0 - jd > 0.5) jd++;
    return FORMAT_Str(16,6,jd/100000.0);
ENDINLINE
ENDFUNCTION

FUNCTION jd_to_cal%:jd,BYREF day%,BYREF month%,BYREF year%,BYREF hour%,BYREF mins%,BYREF secs%
INLINE
bool isBC;
long j1,j2,j3,j4,j5;
double frac,dayfrac,f;
long gregjd = 2299161;
long intgr;

intgr=floor(jd);
frac=jd-intgr;
if (intgr>=gregjd)
{
double tmp;

tmp=floor( ( (intgr - 1867216) - 0.25 ) / 36524.25 );
j1=intgr + 1 + tmp - floor(0.25*tmp);
}
else
{
j1=intgr;
}

dayfrac=frac+0.5;

if (dayfrac>=1.0)
{
dayfrac--;
j1++;
}

j2=j1+1524;
j3=floor(6680.0 + ( (j2 - 2439870) - 122.1 )/365.25);
j4=floor(j3*365.25);
j5=floor( (j2 - j4)/30.6001 );

day=floor(j2 - j4 - floor(j5*30.6001));
month=floor(j5-1);
if (month>12) month-=12;
year=floor(j3-4715);
if (month>2) year--;
if (year<=0) year--;


// get time of day from day fraction
hour=floor(dayfrac * 24.0);
mins=floor((dayfrac*24.0 - hour)*60.0);
f=((dayfrac*24.0 - hour)*60.0 - mins)*60.0;
secs=floor(f);
if (f>0.5) secs++;

if (year<0)
{
isBC=true;
year=-year;
}
else
{
isBC=false;
}

return isBC;
ENDINLINE
ENDFUNCTION

fuzzy70

Quote from: Ian Price on 2012-May-24
You lot obviously have too much time on your hands... ;) :P

I was lucky in that I already wrote the code years ago so all the brain ache of the maths is long behind me lol.

Still have another 100 odd Pascal source files that make up the whole program which the ones I posted are the little baby ones ;)

The whole lot basically works out planetary positions, eclipses, new moons, comet paths etc which I used to control my old telescope.

examples of what can be done with a cheap webcam & sub    £100 telescope.

Lee

Sent from my GT-I5700 using Tapatalk 2

[attachment deleted by admin]
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)