Mikrocontroller und Digitale Elektronik
›
Thread
Funktion: Berechnung WeekOfDay
ZR
Zo R.
(hsch1978)
OP
27.03.2023 10:36
#7380116
Guten Morgen,
für meine Anwendung benötige ich eine Funktion, mit dieser ich den genauen Wochentag ermitteln kann. Als Eingabe wird ein string übergeben:
1
char * Date = "2023-03-20" ;
Im Netz habe ich schon die ein oder andere Funktion gefunden und auch getstet. Leider waren diese Funktionen nicht korrekt, was die Ausgabe betraf.
Gibt es eventuell hier im FOrum jemand der bereits so eine Funktion schon entwickelt hat?
Welche Umgebung?
Eine Lösung für einen Windows-PC wird anders aussehen als eine für einen ARM oder einen AVR .
ZR
Zo R.
(hsch1978)
OP
27.03.2023 10:47
#7380125
Oh sorrry das habe ich vergessen zu sagen.
Es handelt sich hierbei um einem ARM Controller.
He S. schrieb:
Im Netz habe ich schon die ein oder andere Funktion gefunden und auch
getstet. Leider waren diese Funktionen nicht korrekt, was die Ausgabe
betraf.
Wenns bewährt und bereits getestet sein soll, dann kann man mal in den Source-Code eines quelloffenen Linux-Betriebssystems reinschauen.
Mit den Funktionen aus <time.h> und etwas drum herum kann man das machen.
Jahr, Monat, Tag mit sscanf aus dem String lesen.
struct tm füllen, in Epoch umwandeln mit mktime() und damit über localtime() eine (jetzt richtig gefüllte) struct tm beschreiben.
Im Member tm_wday steht dann der Wochentag (Sonntag = 0)
Wenn man nur den Text braucht, geht dann auch gleich strftime()
Quick&Dirty. Verlässt sich voll auf ein gültiges, ISO 8601-Formatiertes Datum im input.
1
#include <stdint.h>
2
#include <time.h>
3
#include <string.h>
4
#include <stdlib.h>
5
6
int dow ( const char * date ) {
7
struct tm myTime ;
8
memset ( & myTime , '\0' , sizeof ( myTime ));
9
myTime . tm_year = atoi ( date );
10
myTime . tm_mon = atoi ( date + 5 ) - 1 ;
11
myTime . tm_mday = atoi ( date + 8 );
12
mktime ( & myTime );
13
return myTime . tm_wday ;
14
}
Statt den drei "atoi"-Zeilen geht evtl. auch ein
strptime(date, "%F", myTime);
1
#include <stdio.h>
2
#include <time.h>
3
4
int main (){
5
struct tm timeinfo = * localtime ( & ( time_t ){ time ( 0 )});
6
printf ( "%.2s \n " , & "SoMoDiMiFrSa" [ timeinfo . tm_wday * 2 ]);
7
return 0 ;
8
}
Die Funktionen kannst du dir in musl libc nachsehen, wie die implementiert sind: https://git.musl-libc.org/cgit/musl/tree/src/time/
Die Aktuellen Zeitzohnendaten kriegt man bei IANA: https://www.iana.org/time-zones
Aber vielleicht reicht ja schon der Teil: http://git.musl-libc.org/cgit/musl/tree/src/time/__secs_to_tm.c
He S. schrieb:
Im Netz habe ich schon die ein oder andere Funktion gefunden und auch
getstet. Leider waren diese Funktionen nicht korrekt, was die Ausgabe
betraf.
Für welchen Zeitraum brauchst du die Funktion.
Muss der Übergang von julianschen auf gregorianischen Kalender mit abgedeckt werden?
ZR
Zo R.
(hsch1978)
OP
27.03.2023 11:22
#7380156
Danke für das Beispiel. Ich habe mal die Funktion getestet. Ich erhalte nicht den richtigen Wochentag. Ich habe die Funktion auch mal genauer mit dem Debugger angeschaut. Der Monat ist immer Monath-1? Warum eigentlich?
Beitrag #7380161 wurde von einem Moderator gelöscht.
ZR
Zo R.
(hsch1978)
OP
27.03.2023 11:32
#7380166
Wenn ich "2023-03-12" eingebe erhalte ich den Wert 1 zurück. Ist aber falsch müsste 7 sein => Sonntag
Mein Fehler: "Year minus 1900" fehlt im Code.
Da steht aber auch die Erklärung für "Monat-1".
1
struct tm {
2
int tm_sec ; /* Seconds [0, 60] */
3
int tm_min ; /* Minutes [0, 59] */
4
int tm_hour ; /* Hour [0, 23] */
5
int tm_mday ; /* Day of the month [1, 31] */
6
int tm_mon ; /* Month [0, 11] (January = 0) */
7
int tm_year ; /* Year minus 1900 */
8
int tm_wday ; /* Day of the week [0, 6] (Sunday = 0) */
9
int tm_yday ; /* Day of the year [0, 365] (Jan/01 = 0) */
10
int tm_isdst ; /* Daylight savings flag */
11
12
long tm_gmtoff ; /* Seconds East of UTC */
13
const char * tm_zone ; /* Timezone abbreviation */
14
};
Sonntag wäre 0, nicht 7.
ZR
Zo R.
(hsch1978)
OP
27.03.2023 11:37
#7380175
Nun stimmt es. Ich habe in der Funktion noch year - 1900 berechnet.
1
int dow ( const char * date )
2
{
3
4
struct tm myTime ;
5
6
memset ( & myTime , '\0' , sizeof ( myTime ));
7
8
myTime . tm_year = atoi ( date ) - 1900 ;
9
myTime . tm_mon = atoi ( date + 5 ) - 1 ;
10
myTime . tm_mday = atoi ( date + 8 );
11
12
mktime ( & myTime );
13
14
return myTime . tm_wday ;
15
16
}
He S. schrieb:
WeekOfDay
oder doch etwa DayOfWeek...?
Gruss Chregu
He S. schrieb:
Wenn ich "2023-03-12" eingebe erhalte ich den Wert 1 zurück. Ist aber
falsch müsste 7 sein => Sonntag
Vielleicht kannst du damit leben, dass Sonntag als 1 definiert ist.
Alternativ könntest du immer 5 dazuzählen und dann mit modulo(x,7)+1 auf deine Darstellung umrechnen.
He S. schrieb:
erhalte ich den Wert 1 zurück. Ist aber falsch müsste 7 sein => Sonntag
Der Sonntag IST der 1. Tag in der Woche!
(Daniel 7,25)
Gruss Chregu
Christian M. schrieb:
Der Sonntag IST der 1. Tag in der Woche!
(Daniel 7,25)
Und Samstag war der sechste Tag (1.Mose 1:31) und Sonntag wurde ausgeruht ...
Christian M. schrieb:
He S. schrieb:
erhalte ich den Wert 1 zurück. Ist aber falsch müsste 7 sein => Sonntag
Der Sonntag IST der 1. Tag in der Woche!
(Daniel 7,25)
https://www.timeanddate.com/calendar/days/first-day-of-the-week.html
ZR
Zo R.
(hsch1978)
OP
28.03.2023 08:42
#7380874
Danke nochmals für eure Untersützung.
Ich habe allerdings noch ein Problem mit einer Konvertierung:
Ich möchte das Datum in einen string umwandeln für die weitere Verarbeitung.
Dazu nutze ich die Funktion strftime:
Datum Zeit:
1
sec = 30
2
min = 59
3
hour = 9
4
month_day = 27
5
month = 3
6
year = 123
7
day_of_week = 4
8
day_of_year 117
9
time_zone = 100663296
Nun soll mit Hilfe der Funktion strftime diese obigen Werete in ein string umgewandlet werden:
1
char buffer [ 10 ];
2
strftime ( buffer , 10 , "%Y:%m:%d" , & DateTime );
Im Buffer steht dann folgendes:
1
buffer [ 0 ] char 50 '2' 0x20000780
2
buffer [ 1 ] char 48 '0' 0x20000781
3
buffer [ 2 ] char 50 '2' 0x20000782
4
buffer [ 3 ] char 51 '3' 0x20000783
5
buffer [ 4 ] char 58 ':' 0x20000784
6
buffer [ 5 ] char 48 '0' 0x20000785
7
buffer [ 6 ] char 52 '4' 0x20000786
8
buffer [ 7 ] char 58 ':' 0x20000787
9
buffer [ 8 ] char 50 '2' 0x20000788
10
buffer [ 9 ] char 55 '7' 0x20000789
Das stimmt aber nicht. Der zweite Wert sollte nicht 4 sein sondern 3.
He S. schrieb:
Das stimmt aber nicht. Der zweite Wert sollte nicht 4 sein sondern 3.
Nochmal:
Εrnst B. schrieb:
1
struct tm {
2
int tm_sec ; /* Seconds [0, 60] */
3
int tm_min ; /* Minutes [0, 59] */
4
int tm_hour ; /* Hour [0, 23] */
5
int tm_mday ; /* Day of the month [1, 31] */
6
int tm_mon ; /* Month [0, 11] (January = 0) */
7
int tm_year ; /* Year minus 1900 */
8
int tm_wday ; /* Day of the week [0, 6] (Sunday = 0) */
9
int tm_yday ; /* Day of the year [0, 365] (Jan/01 = 0) */
10
int tm_isdst ; /* Daylight savings flag */
11
long tm_gmtoff ; /* Seconds East of UTC */
12
const char * tm_zone ; /* Timezone abbreviation */
13
};
Überleg dir, was der Kommentar "January = 0" für die Monate Februar, März, April... aussagt.
ZR
Zo R.
(hsch1978)
OP
28.03.2023 10:48
#7380963
Verdammt das habe ich völlig übersehen. Danke dir.
He S. schrieb:
2023-03-20
= 2000
RG
Ron-Hardy G.
(ron-hardy)
(Firma: LinTech GmbH)
28.03.2023 11:09
#7380977
Εrnst B. schrieb:
struct tm {
int tm_sec; /* Seconds [0, 60] */
wieso 60 ?
Ron-Hardy G. schrieb:
wieso 60 ?
Schaltsekunde?
RG
Ron-Hardy G.
(ron-hardy)
(Firma: LinTech GmbH)
28.03.2023 11:21
#7380986
Harald K. schrieb:
Schaltsekunde?
ok, danke
Ich habe mal die Gauss'sche Osterformel benutzt. Ein altes Foto vom Ostersonntag, ohne Jahresangabe. Ein kleines Basic-Programm lieferte mir die Hauptverdächtigen (Aus der Mode der abgebildeten Kleidung ließ es sich etwa abschätzen).
https://de.wikipedia.org/wiki/Gau%C3%9Fsche_Osterformel
da spielt noch der Vollmondtermin eine Rolle, das macht es etwas komplizierter.
void rtc_update_dofw_and_week(TimeDate *ptr) {
if (ptr != NULL) {
unsigned int x_year = 1900;
unsigned int y_month = 1;
1
if (ptr->year >= 2000) {
2
ptr->dofw_calendar = 5;//first day of year 2000 Szombat
3
for (x_year = 2000; x_year < ptr->year; x_year++) {
4
for (y_month = 1; y_month <= 12; y_month ++) {
5
ptr->dofw_calendar += rtc_get_day_in_month(x_year, y_month);
6
ptr->dofw_calendar %= 7;
7
}
8
}
9
}
10
{
11
unsigned char i = 0;
12
ptr->week_calendar = 0;
13
if (ptr->dofw_calendar < 3) {
14
ptr->week_calendar ++;
15
}
16
17
for (i = 1; i < ptr->month; i++) {
18
ptr->dofw_calendar += rtc_get_day_in_month(ptr->year, i) % 7;
19
ptr->week_calendar += rtc_get_day_in_month(ptr->year, i) / 7;
20
}
21
ptr->dofw_calendar += (ptr->day - 1) % 7;
22
ptr->week_calendar += (ptr->day - 1) / 7;
23
ptr->week_calendar += ptr->dofw_calendar / 7;
24
ptr->dofw_calendar = ptr->dofw_calendar % 7;
25
}
}
}
unsigned char rtc_is_leap_year(unsigned int year) {
unsigned char result = 0;
if ((year % 400) == 0) {
result = 1;
} else {
if ((year % 100) == 0) {
result = 0;
} else {
if ((year % 4) == 0) {
result = 1;
} else {
result = 0;
}
}
}
return result;
}
unsigned char rtc_get_day_in_month(unsigned int year, unsigned int month) {
unsigned char result = 1;
if ((month >= MONTH_MIN) && (month <= MONTH_MAX)) {
if ((month == 2) && (rtc_is_leap_year(year) == 1)) {
result = day_in_month[MONTH_LEAP];
} else {
result = day_in_month[month];
}
}
return result;
}
He S. schrieb:
char buffer[10];
strftime (buffer, 10, "%Y:%m:%d", &DateTime);
10 ist zu kurz für einen C-String.
Da ist kein Platz für die '\0'
He S. schrieb:
time_zone = 100663296
Warum diese kryptische Zahl und nicht einfach 0x6000000?
He S. schrieb:
Das stimmt aber nicht. Der zweite Wert sollte nicht 4 sein
sondern 3.
He S. schrieb:
day_of_year 117
Der 117. Tag des Jahres paßt aber auch besser in den April, als in den März.
Εrnst B. schrieb:
He S. schrieb:
Das stimmt aber nicht. Der zweite Wert sollte nicht 4 sein sondern 3.
Nochmal:
Εrnst B. schrieb: struct tm {
int tm_sec; /* Seconds [0, 60] /
int tm_min; / Minutes [0, 59] /
int tm_hour; / Hour [0, 23] /
int tm_mday; / Day of the month [1, 31] */
....
};
Kann nicht mal wer diese Info in ein Youtube-Video packen? Entsprechend dem Niveau der "Programmierer" hier - denn schnödes Lesen ist ja so was von altbacken ...
Joe L. schrieb:
denn schnödes Lesen ist ja so was von altbacken ...
Dann lass es dir halt vorlesen. (Gibt ja programme dafür)
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.
Noch kein Account?
Die Registrierung ist kostenlos und dauert nur eine Minute.
Jetzt registrieren