I need a function that will give the week number of the month from micros without using libraries. Signature of function to better understand what I mean: getWeekOfMonth(long timestamp, int m, isLeapYear(y))
.
I searched the Internet to find some information, but there is only information about how to write with libraries.
CodePudding user response:
First you need to define timestamp correctly. You need a starting date/time where your time is equal to zero. This is usually called epoch (in astronomy).
From this there are 2 approaches to get the year,month,week,dayofweek. Either you handle any time change relatively to lastly computed date/time or you compute the stuff using modular arithmetics and rules...
I prefer the first one as I often deal with astronomy times where there are many irregular corrections of time that would be too complicated to code with the second approach but its slower.
The basic rules are:
leap year is every 4 years but not every 100 except every 400 years
february has 1 day more in leap year
so naive version of 2nd approach can look like this in C on integers (if t
is number in days from 1.1.0000 00:00:00
):
const int months[2][12]= {{ 31,28,31,30,31,30,31,31,30,31,30,31 }, // normal
{ 31,29,31,30,31,30,31,31,30,31,30,31 }}; // leap
year = t/(4*365 1); t -= year*(4*365 1);
year = t/365; t -= 365*(t/365);
leap = ((year % 4 == 0) AND (year % 100 != 0)) OR (year % 400 == 0)
for (month=0;month<12;)
if (t>months[leap][month]){ t-=months[leap][month]; month ; }
else break;
now day of week and week of month can be done in similar fashion (note I did not test code above I just wrote it directly in here). Also beware I count months from 0 so if you want to print them just use increment.
The 1st approach I am usually doing like this (tested and heavily used ancient C code hope I did not forget to copy something):
//---------------------------------------------------------------------------
const double t_rok=365.242195601852; // tropick year in days
const double t_den= 1.0; // mean stellar day
const double t_hod=t_den/24.0;
const double t_min=t_hod/60.0;
const double t_sec=t_min/60.0;
const double time_t0 =0.0; // epoch
const int time_den7=5; // sobota (saturday)
const int time_den0=0;
const int time_mes0=0;
const int time_rok0=2000;
const int time_kalen[2][12]= {{ 31,28,31,30,31,30,31,31,30,31,30,31 }, // normal
{ 31,29,31,30,31,30,31,31,30,31,30,31 }}; // priestupny
const AnsiString time_week[7]= { "Pondelok","Utorok","Streda","Stvrtok","Piatok","Sobota","Nedela" };
//---------------------------------------------------------------------------
class time_
{
public:
int den,mes,rok,den7; // day ,month, year,
int hod,min,sec;
double _tr0,_tr1; // t on start if this and next year
double t,ut,dut,JD,jd; // t is SEC 1 hod, ut is universal time,dut is shift -1*t_hod or -2 hod*t_hod (summer/winter), JD is julian date, jd is "jullian" after year 2000
time_() {den7=time_den7;t=time_t0;den=time_den0;mes=time_mes0;rok=time_rok0;hod=0;min=0;sec=0;_tr0=0;_tr1=365;if(priestupny(rok))_tr1 ;setut();}
time_(time_& a){ *this=a; }; ~time_(){}; time_* operator = (const time_ *a) { *this=*a; return this; }; /*time_* operator = (const time_ &a) { ...copy... return this; };*/
int priestupny(int rok); // leap year?
void date(int,int,int,int,int,int);
void time(double); // this sets time absolutely
void add_time(double); // this adds to actual time relatively
void setut(); // this updates ut
void inc_rok(); // helper function for year change
void dec_rok(); // helper function for year change
void set_actual_time(); // this loads actual system time
AnsiString str0(); // string output: d.m.yyyy hh:mm:ss day
AnsiString str1(); // string output: UT = hh:mm:ss
};
//---------------------------------------------------------------------------
int time_::priestupny(int r)
{
int p=0; // priestupny rok ?
if (r% 4==0) p=1;
if (r0==0) p=0;
if (r@0==0) p=1;
return p;
}
//---------------------------------------------------------------------------
void time_::inc_rok()
{
rok ;
_tr0=_tr1;
_tr1 =365;
if (priestupny(rok)) _tr1 ;
}
//---------------------------------------------------------------------------
void time_::dec_rok()
{
rok--;
_tr1=_tr0;
_tr0-=365;
if (priestupny(rok)) _tr0--;
}
//---------------------------------------------------------------------------
void time_::date(int d,int m,int r,int hh,int mm,int ss)
{
if ((m<1)||(m>12)||(d<1)||(d>31)) return; // prevent freeze on invalid date
int ki,pr;
d--;
m--;
t=floor(t);
pr=priestupny(rok);
ki= 1;
if (d>den) ki= 1; if (d<den) ki=-1;
if (m>mes) ki= 1; if (m<mes) ki=-1;
if (r>rok) ki= 1; if (r<rok) ki=-1;
while((r!=rok)||(m!=mes)||(d!=den))
{
t =ki;
den =ki;
if ((ki>0)&&(den>=time_kalen[pr][mes]))
{
mes ;
if (mes>=12)
{
mes=0;
inc_rok();
pr=priestupny(rok);
}
den=0;
}
if ((ki<0)&&(den<0))
{
mes--;
if (mes<0){
mes=11;
dec_rok();
pr=priestupny(rok);
}
den=time_kalen[pr][mes]-1;
}
}
hod=hh;
min=mm;
sec=ss;
t =hod/24.0;
t =min/1440.0;
t =sec/86400.0;
setut();
}
//---------------------------------------------------------------------------
void time_::time(double dt)
{
add_time(dt-t);
}
//---------------------------------------------------------------------------
void time_::add_time(double dt)
{
double q;
int pr;
t =dt;
q=t-_tr0;
while (q<0)
{
dec_rok();
q =(_tr1-_tr0);
}
while (q _tr0>=_tr1)
{
q-=(_tr1-_tr0);
inc_rok();
}
pr=priestupny(rok);
den=floor(q);
mes=0;
while(den>=time_kalen[pr][mes])
{
den-=time_kalen[pr][mes];
mes ;
if (mes>=12) { mes=0; den=0; rok=0; } // if error
}
q=t-floor(t);
if (q<0) q ;
q*=24.0; hod=floor(q); q-=hod;
q*=60.0; min=floor(q); q-=min;
q*=60.0; sec=floor(q);
setut();
}
//---------------------------------------------------------------------------
void time_::set_actual_time()
{
struct date ddd;
struct time ttt;
getdate(&ddd);
gettime(&ttt);
date( ddd.da_day,ddd.da_mon,ddd.da_year,ttt.ti_hour, ttt.ti_min, ttt.ti_sec);
}
//---------------------------------------------------------------------------
AnsiString time_::str0()
{
AnsiString s;
s="";
s.sprintf("%.0i.%.0i.%.0i i:i:i ",den 1,mes 1,rok,hod,min,sec);
return s time_week[den7];
}
//---------------------------------------------------------------------------
AnsiString time_::str1()
{
AnsiString s;
double q;
s="";
q=hod floor(dut/t_hod);
while (q>=24.0) q-=24.0;
while (q< 0.0) q =24.0;
s.sprintf("UT = %2.0f:%2i:%2i ",q,min,sec);
return s;
}
//---------------------------------------------------------------------------
void time_::setut()
{
den7=int(floor(t) time_den7)%7; if (den7<0) den7 =7;
dut=-2.0*t_hod;
if (mes>2) dut=-2.0*t_hod;
if (mes>9) dut=-1.0*t_hod;
ut=t dut;
jd=ut 0.478;
JD=jd 2451544.0;
// posledna Nedela v marci 02:00 -> 03:00 ... dut=-2*t_hod
// posledna Nedela v oktobti 03:00 -> 02:00 ... dut=-1*t_hod
}
//---------------------------------------------------------------------------
Just translate the slavic names of days of week (Pondelok,Utorok...) also "Priestupny" means leap year. I am too lazy for that. The code expects time where integer part is day (from epoch) and fractional part hold time and it convert it to date and UT it
time (winter/summer time shift included) and also Julian date JD
as I use this for astronomy purposes
Now in order to add your week of month you need to process your month start day and count weeks from actual month. In the first approach just add something like this:
const int months[2][12]= {{ 31,28,31,30,31,30,31,31,30,31,30,31 }, // normal
{ 31,29,31,30,31,30,31,31,30,31,30,31 }}; // leap
year = t/(4*365 1); t -= year*(4*365 1);
year = t/365; t -= 365*(t/365);
leap = ((year % 4 == 0) AND (year % 100 != 0)) OR (year % 400 == 0)
for (month=0;month<12;)
if (t>months[leap][month]){ t-=months[leap][month]; month ; }
else break;
weekofmonth = t/7;
in the second approach you can do the same as t-_tr0
is time in days from start of this year so:
tt=t-_tr0;
for (month=0;month<12;)
if (tt>months[leap][month]){ tt-=months[leap][month]; month ; }
else break;
weekofmonth = tt/7;