ich möchte folgendes machen:
Methode:
CString GetKalenderwoche(CString sDate)
Frage:
Wie?
Mit der Klasse CTime finde ich nichts.
Danke.
Gruss Alex
--
_____________________________________________________________
NewsGroups Suchen, lesen, schreiben mit http://netnews.web.de
> CString GetKalenderwoche(CString sDate)
Musst du IMHO selbst ausrechnen, wobei bei uns der 1.1. noch zur letzten
Woche des alten Jahres gehört, wenn er auf Freitag, Samstag oder Sonntag
fällt.
Beachte, dass das nicht weltweit einheitlich ist - in Amerika (zumindest
Lotus Notes) gibt es eine andere Regel, was alle paar Jahre (5-7 ?) zu
anderen Wochennummern führt.
Wolfgang
Schau mal in der MSDN unter: strftime, wcsftime
da is auch ein kleines nettes Beispiel dabei.
HTH Gerald
..und
CTime::Format(..)
Schiko
[Kalenderwoche]
>CTime::Format(..)
Fuer die amerikanische Rechenweise vielleicht (%U,%W), aber was ist mit
unserer hochheiligen DIN 1355 respektive ISO 8601?
Versuch einer Implementierung, gibt aber keine Garantien irgendwelcher
Art dazu: http://www.carsti.de/sources/Calendarweek.zip
Carsten Witte [MVP]
--
mpvcFAQ : http://www.albert-weinert.de/vcfaq/html.htm
CodeGuru : http://www.codeguru.com
Private : http://www.carsti.de/dmfc.html
Ich beantworte keine Fragen, die per e-mail eingehen!
Da kann ich momentan nur einen interessanten Link anbieten:
http://xarch.tu-graz.ac.at/publ/tutorial/perl/activestate/html/site/lib/Date/Calc.html
Schönen Gruss
Gerald
falls es sich lohnt, generell einen eigenen Parser in der Form:
CString strAusgabe = BesondersUmfangreichesFormat( tCurrent );
In Pflichtenheften angegeben wurde von uns ein Auszug aus der MSDN:strftime,
alles andere ( incl. DIN 1355 respektive ISO 8601 ) extra $.
<schnippel>
// Backslash gefunden
nFormat++;
if( nFormat < nLength )
{
chCur = strFormat[nFormat];
if(chCur == chFSpec)// Zeichen ist wirklich'\'->weitersuchen
{
strNew[nNewLine] = chCur;
nNewLine++;
nFormat++;
continue;
}
switch(chCur) file://Formatspecifier entdeckt
{
case 'U': file://Kalenderwoche A-Z,a-z, start mit Montag
nTimePart = atoi(tCur.Format("%W"));
strNew[nNewLine] = nTimePart + 'A';
if(strNew[nNewLine] > 'Z')
strNew[nNewLine] += 6;
nNewLine ++;
break;
case 'w': file://Wochentag 1-7, start mit Montag
nTimePart = atoi(tCur.Format("%w"));
if(nTimePart == 0)
nTimePart = 7;
strNew[nNewLine] = nTimePart + 48;//48='0'
nNewLine ++;
break;
<schnippel>
strNew[nNewLine] = '\0';
return tCur.Format(strNew);
Schiko
Hallo Alex -
ich hatte gestern - nach langer Pause - erst wieder in die
Newsgroups geschaut. Ich hoffe, Du entdeckst meine Antwort
noch.
Ich hatte genau Dein Problem, und die Antworten auf Deine Frage
zeigten, dass man selber basteln muss. Carsten Wittes
Loesung war mir zu aufwendig. Ich habe halt selber "gebastelt".
Pruefe mal die folgende Routine (allerdings mit MFC gemacht).
Gruss Udo
-------------------------------------------------------
// Berechnung der Kalenderwoche
int KalenderWoche( CTime ct )
{
// DIN wird verwendet
int WochenTag = ct.GetDayOfWeek() - 1; //Montag soll =1 sein
if( WochenTag == 0 ) WochenTag = 7; // und Sonntag soll =7 sein
//Normung auf den Donnerstag der zugehörigen Woche.
// Dieser Donnerstag kann in einem anderen Jahr liegen:
CTimeSpan ts( 4-WochenTag, 0, 0, 0 );
CTime tDo = ct + ts;
tm * tGMT = tDo.GetGmtTm( ); //Konvertiert "CTime" in Struktur
int TagNr = tGMT->tm_yday + 1; //Tag-Nr. im Jahr (ab 1 = 1.Jan.)
int KW = TagNr / 7;
int Do1 = TagNr - KW*7; //Rest = Tag-Nr. des ersten Do.
// in dem Jahr, wenn >0
//Rest = 0: Der 1. Jan. ist ein Donnerstag; dann stimmt die
// Wochenanzahl schon.
if( Do1 > 0 ) KW += 1; //Wenn Rest > 0: noch eine Kalenderwoche dazu!
return KW;
}
----------------------------------------------------------
habe Dein Beitrag gerade gelesen.
Ich machs eigentlich jetzt ganz einfach.
CTime::Format
%W
Week of year as decimal number, with Monday as first day of week (00 - 53)
strftime, wcsftime
Format a time string.
Siehst Du in dieser Funktion Probleme?
Gruss Alex
"Udo Huebner" <udo.h...@t-online.de> schrieb im Newsbeitrag
news:3A9EDBDA...@t-online.de...
> Alex Basler wrote:
> >
> > Hallo,
> >
> > ich möchte folgendes machen:
> >
> > Methode:
> > CString GetKalenderwoche(CString sDate)
> >
> > Frage:
> > Wie?
> >
> > Mit der Klasse CTime finde ich nichts.
>
> Hallo Alex -
> ich hatte gestern - nach langer Pause - erst wieder in die
> Newsgroups geschaut. Ich hoffe, Du entdeckst meine Antwort
> noch.
> Ich hatte genau Dein Problem, und die Antworten auf Deine Frage
> zeigten, dass man selber basteln muss. Carsten Wittes
> Loesung war mir zu aufwendig. Ich habe halt selber "gebastelt".
> Pruefe mal die folgende Routine (allerdings mit MFC gemacht).
>
> Gruss Udo
>
> -------------------------------------------------------
> // Berechnung der Kalenderwoche
>
> int KalenderWoche( CTime ct )
> {
> // DIN wird verwendet
> int WochenTag = ct.GetDayOfWeek() - 1; file://Montag soll =1 sein
> if( WochenTag == 0 ) WochenTag = 7; // und Sonntag soll =7 sein
>
> file://Normung auf den Donnerstag der zugehörigen Woche.
> // Dieser Donnerstag kann in einem anderen Jahr liegen:
> CTimeSpan ts( 4-WochenTag, 0, 0, 0 );
> CTime tDo = ct + ts;
>
> tm * tGMT = tDo.GetGmtTm( ); file://Konvertiert "CTime" in Struktur
> int TagNr = tGMT->tm_yday + 1; file://Tag-Nr. im Jahr (ab 1 = 1.Jan.)
>
> int KW = TagNr / 7;
> int Do1 = TagNr - KW*7; file://Rest = Tag-Nr. des ersten Do.
> // in dem Jahr, wenn >0
> file://Rest = 0: Der 1. Jan. ist ein Donnerstag; dann stimmt die
> // Wochenanzahl schon.
> if( Do1 > 0 ) KW += 1; file://Wenn Rest > 0: noch eine Kalenderwoche
dazu!
>
> return KW;
> }
> ----------------------------------------------------------
Teste das doch mal mit einem "worst case" Schaltjahr wie 1976:
1976-W01-1 = 29.12.1975 bis
1976-W53-7 = 02.01.1977
oder einem nicht-Schaljahr wie 1999:
1999-W01-1 = 04.01.1999
1999-W52-7 = 02.01.2000
mfg
-herbert menke
Hallo Alex -
ich habe
CTime::Format
%W
ausprobiert, und es liefert für
Mittwoch, 31.12.1997 die Kalenderwoche 52
Donnerstag, 1.1.1998 die Kalenderwoche 0.
Beide sind nach DIN falsch! Es ist offenbar die amerikanische Zählung.
Nach DIN ist die Woche mit dem 1. Donnerstag des Jahres die 1.
Kalenderwoche. Also mußte in beiden Fällen die "1. Kalenderwoche"
herauskommen. Der Mittwoch gehört zur Kalenderwoche 1 des Jahres 1998!
Wozu ist eigentlich strftime, wcsftime in Deinem Post gedacht?
Die Zeile
CString s = m_dtPicker.Format( "%W" );
(wobei m_dtPicker aus meinem vorigen Post stammt) liefert in s doch
schon den richtigen String. Offenbar habe jetzt ich etwas nicht
verstanden.
Gruß Udo
Hallo Herbert -
hier nochmals - neben unseren emails - meine Ansicht für die
Leser der News:
Die Regel für Kalenderwochen ist:
Die Woche mit dem 1. Donnerstag im Jahr ist die 1. Kalenderwoche
des Jahres.
Also z. B.
04.01.1999 ist Kalenderwoche 1
02.01.2000 ist Kalenderwoche 52 des vorigen Jahres 1999 (!)
ebenso:
29.12.1975 ist Kalenderwoche 1 des Jahres 1976 (!)
02.01.1977 ist Kalenderwoche 53 des Jahres 1976 (!)
Danach arbeitet meine Routine richtig.
Ich habe darauf verzichtet, an den Tagen mit Ausrufezeichen
die Kalenderwoche auf Null zu setzen - was ja auch keinen rechten
Sinn macht.
Gruß Udo
Udo Huebner <udo.h...@t-online.de> wrote:
>Wozu ist eigentlich strftime, wcsftime in Deinem Post gedacht?
>Die Zeile
> CString s = m_dtPicker.Format( "%W" );
>(wobei m_dtPicker aus meinem vorigen Post stammt) liefert in s doch
>schon den richtigen String. Offenbar habe jetzt ich etwas nicht
>verstanden.
Hier kannst Du nachlesen, was es für Formatierungen es gibt.
CTime verwendet ja die gleichen, wie die Funktion strftime
HTH Alex
##############################################################
strftime, wcsftime
Format a time string.
size_t strftime( char *strDest, size_t maxsize, const char *format, const struct
tm *timeptr );
size_t wcsftime( wchar_t *strDest, size_t maxsize, const wchar_t *format, const
struct tm *timeptr );
Routine Required Header Compatibility
strftime <time.h> ANSI, Win 95, Win NT
wcsftime <time.h> or <wchar.h> ANSI, Win 95, Win NT
For additional compatibility information, see Compatibility in the Introduction.
Libraries
LIBC.LIB Single thread static library, retail version
LIBCMT.LIB Multithread static library, retail version
MSVCRT.LIB Import library for MSVCRT.DLL, retail version
Return Value
strftime returns the number of characters placed in strDest if the total number
of resulting characters, including the terminating null, is not more than maxsize.
wcsftime returns the corresponding number of wide characters. Otherwise, the
functions return 0, and the contents of strDest is indeterminate.
Parameters
strDest
Output string
maxsize
Maximum length of string
format
Format-control string
timeptr
tm data structure
Remarks
The strftime and wcsftime functions format the tm time value in timeptr
according to the supplied format argument and store the result in the buffer
strDest. At most, maxsize characters are placed in the string. For a description
of the fields in the timeptr structure, see asctime. wcsftime is the wide-
character equivalent of strftime; its string-pointer argument points to a wide-
character string. These functions behave identically otherwise.
Note Prior to this version of Visual C++, the documentation described the
format parameter of wcsftime as having the datatype const wchar_t *, but the
actual implementation of the format datatype was const char *. In this version,
the implementation of the format datatype has been updated to reflect the
previous and current documentation, that is: const wchar_t *.
Generic-Text Routine Mappings
TCHAR.H Routine _UNICODE & _MBCS Not Defined _MBCS Defined _UNICODE Defined
_tcsftime strftime strftime wcsftime
The format argument consists of one or more codes; as in printf, the formatting
codes are preceded by a percent sign (%). Characters that do not begin with % are
copied unchanged to strDest. The LC_TIME category of the current locale affects
the output formatting of strftime.(For more information on LC_TIME, see setlocale.
) The formatting codes for strftime are listed below:
%a
Abbreviated weekday name
%A
Full weekday name
%b
Abbreviated month name
%B
Full month name
%c
Date and time representation appropriate for locale
%d
Day of month as decimal number (01 – 31)
%H
Hour in 24-hour format (00 – 23)
%I
Hour in 12-hour format (01 – 12)
%j
Day of year as decimal number (001 – 366)
%m
Month as decimal number (01 – 12)
%M
Minute as decimal number (00 – 59)
%p
Current locale‚s A.M./P.M. indicator for 12-hour clock
%S
Second as decimal number (00 – 59)
%U
Week of year as decimal number, with Sunday as first day of week (00 – 53)
%w
Weekday as decimal number (0 – 6; Sunday is 0)
%W
Week of year as decimal number, with Monday as first day of week (00 – 53)
%x
Date representation for current locale
%X
Time representation for current locale
%y
Year without century, as decimal number (00 – 99)
%Y
Year with century, as decimal number
%z, %Z
Time-zone name or abbreviation; no characters if time zone is unknown
%%
Percent sign
As in the printf function, the # flag may prefix any formatting code. In that
case, the meaning of the format code is changed as follows.
Format Code Meaning
%#a, %#A, %#b, %#B, %#p, %#X, %#z, %#Z, %#% # flag is ignored.
%#c Long date and time representation, appropriate for current locale. For
example: “Tuesday, March 14, 1995, 12:41:29„.
%#x Long date representation, appropriate to current locale. For example:
“Tuesday, March 14, 1995„.
%#d, %#H, %#I, %#j, %#m, %#M, %#S, %#U, %#w, %#W, %#y, %#Y Remove leading zeros
(if any).
Example
/* TIMES.C illustrates various time and date functions including:
* time _ftime ctime asctime
* localtime gmtime mktime _tzset
* _strtime _strdate strftime
*
* Also the global variable:
* _tzname
*/
#include <time.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <string.h>
void main()
{
char tmpbuf[128], ampm[] = "AM";
time_t ltime;
struct _timeb tstruct;
struct tm *today, *gmt, xmas = { 0, 0, 12, 25, 11, 93 };
/* Set time zone from TZ environment variable. If TZ is not set,
* the operating system is queried to obtain the default value
* for the variable.
*/
_tzset();
/* Display operating system-style date and time. */
_strtime( tmpbuf );
printf( "OS time:\t\t\t\t%s\n", tmpbuf );
_strdate( tmpbuf );
printf( "OS date:\t\t\t\t%s\n", tmpbuf );
/* Get UNIX-style time and display as number and string. */
time( <ime );
printf( "Time in seconds since UTC 1/1/70:\t%ld\n", ltime );
printf( "UNIX time and date:\t\t\t%s", ctime( <ime ) );
/* Display UTC. */
gmt = gmtime( <ime );
printf( "Coordinated universal time:\t\t%s", asctime( gmt ) );
/* Convert to time structure and adjust for PM if necessary. */
today = localtime( <ime );
if( today->tm_hour > 12 )
{
strcpy( ampm, "PM" );
today->tm_hour -= 12;
}
if( today->tm_hour == 0 ) /* Adjust if midnight hour. */
today->tm_hour = 12;
/* Note how pointer addition is used to skip the first 11
* characters and printf is used to trim off terminating
* characters.
*/
printf( "12-hour time:\t\t\t\t%.8s %s\n",
asctime( today ) + 11, ampm );
/* Print additional time information. */
_ftime( &tstruct );
printf( "Plus milliseconds:\t\t\t%u\n", tstruct.millitm );
printf( "Zone difference in seconds from UTC:\t%u\n",
tstruct.timezone );
printf( "Time zone name:\t\t\t\t%s\n", _tzname[0] );
printf( "Daylight savings:\t\t\t%s\n",
tstruct.dstflag ? "YES" : "NO" );
/* Make time for noon on Christmas, 1993. */
if( mktime( &xmas ) != (time_t)-1 )
printf( "Christmas\t\t\t\t%s\n", asctime( &xmas ) );
/* Use time structure to build a customized time string. */
today = localtime( <ime );
/* Use strftime to build a customized time string. */
strftime( tmpbuf, 128,
"Today is %A, day %d of %B in the year %Y.\n", today );
printf( tmpbuf );
}
Output
OS time: 21:51:03
OS date: 05/03/94
Time in seconds since UTC 1/1/70: 768027063
UNIX time and date: Tue May 03 21:51:03 1994
Coordinated universal time: Wed May 04 04:51:03 1994
12-hour time: 09:51:03 PM
Plus milliseconds: 279
Zone difference in seconds from UTC: 480
Time zone name:
Daylight savings: YES
Christmas Sat Dec 25 12:00:00 1993
Today is Tuesday, day 03 of May in the year 1994.
Hallo Alex -
danke für die Info aber das habe ich schon. Mich interessierte
eigentlich nur, warum strftime von Dir noch erwähnt wurde.
Wichtiger ist mir: Was sagst Du zu meinen Einwänden bei Deinem
Verfahren? Du hattest gefragt, ob ich in Deinem Verfahren
Probleme sehe. Ich sah sie. Bist Du meiner Meinung, daß
CTime::Format
%W
in Deutschland zu Fehlern führt, oder habe ich etwas übersehen?
Gruß Udo
>Wichtiger ist mir: Was sagst Du zu meinen Einwänden bei Deinem
>Verfahren? Du hattest gefragt, ob ich in Deinem Verfahren
>Probleme sehe. Ich sah sie. Bist Du meiner Meinung, daß
> CTime::Format
> %W
>in Deutschland zu Fehlern führt, oder habe ich etwas übersehen?
Ich weiß es nicht.
Deine Funktion funktioniert auf jeden Fall. Wie es bei Worst Case aussieht kann
ich nicht beurteilen.
//Normung auf den Donnerstag der zugehörigen Woche.
//Dieser Donnerstag kann in einem anderen Jahr
Woher hast Du diese Info? DIN Buch?
Gruss Alex
int KalenderWoche( CTime ct )
{
// DIN wird verwendet
int WochenTag = ct.GetDayOfWeek() - 1; //Montag soll =1 sein
if( WochenTag == 0 ) WochenTag = 7; // und Sonntag soll =7 sein
//Normung auf den Donnerstag der zugehörigen Woche.
// Dieser Donnerstag kann in einem anderen Jahr liegen:
CTimeSpan ts( 4-WochenTag, 0, 0, 0 );
CTime tDo = ct + ts;
tm * tGMT = tDo.GetGmtTm( ); //Konvertiert "CTime" in Struktur
int TagNr = tGMT->tm_yday + 1; //Tag-Nr. im Jahr (ab 1 = 1.Jan.)
int KW = TagNr / 7;
int Do1 = TagNr - KW*7; //Rest = Tag-Nr. des ersten Do.
// in dem Jahr, wenn >0
//Rest = 0: Der 1. Jan. ist ein Donnerstag; dann stimmt die
// Wochenanzahl schon.
if( Do1 > 0 ) KW += 1; //Wenn Rest > 0: noch eine Kalenderwoche dazu!
return KW;
}
--
habe jetzt doch noch weiterprobiert.
// ** 31.12.1997
CTime t2( 1997, 12, 31, 0, 0, 0 ); // Jahr, Monat, Tag
CString sDatum = t2.Format("Kalenderwoche: %W, Tag: %w");
nKW1 = KalenderWoche(t2);
sDatum = {"Kalenderwoche: 52, Tag: 3"}
nKW1 = 53
CTime t3( 1998, 1, 1, 0, 0, 0 ); // Jahr, Monat, Tag
sDatum = t3.Format("Kalenderwoche: %W, Tag: %w");
nKW1 = KalenderWoche(t2);
sDatum= {"Kalenderwoche: 00, Tag: 4"}
nKW1 = 53
Ich denke jetzt schon dass es passt.
Hast Du noch eine Adresse, wo ich dies noch schriftlich finde?
//Die Regel für Kalenderwochen ist:
//Die Woche mit dem 1. Donnerstag im Jahr ist die 1. Kalenderwoche
//des Jahres.
//Also z. B.
//04.01.1999 ist Kalenderwoche 1
//02.01.2000 ist Kalenderwoche 52 des vorigen Jahres 1999 (!)
//ebenso:
//29.12.1975 ist Kalenderwoche 1 des Jahres 1976 (!)
//02.01.1977 ist Kalenderwoche 53 des Jahres 1976 (!)
Gruss Alex
>Ich denke jetzt schon dass es passt.
>Hast Du noch eine Adresse, wo ich dies noch schriftlich finde?
http://www.salesianer.de/util/kalfaq.html#B3
>//Die Regel für Kalenderwochen ist:
Du kannst eventuelle mal Deine Ergebnisse mit meiner Impelementation von
einst im Mai http://www.carsti.de/sources/Calendarweek.zip vergleichen.
Das wurde mal fuer korrekt befunden...
Hat eigentlich mal jemand getestet, ob sich %w von strftime an die
gesetzte Loacal haelt? Also vielleicht die php3 Version %v emuliert.
ich glaub jetzt ist die Verwirrung komplett!
Die von Carsten angegebene Adresse
http://www.salesianer.de/util/kalwoch.html
gibt nämlich bei 31.12.1997 folgendes aus:
Mittwoch, KW1
Die Lösung von Udo Mittwoch KW53 ????
function kalenderwoche(datum) {
var jh=datum.getYear(); if(jh<1900) jh+=1900; // Anm. 1
jh++; // Anm. 2
var kalwo=kaldiff(datum,jh);
while(kalwo<1) { jh--; kalwo=kaldiff(datum,jh); }
return kalwo;
}
function kaldiff(datum,jahr) {
var d4j=new Date(jahr,0,4);
var wt4j=(d4j.getDay()+6)%7; // Anm. 3
return Math.floor(1.05+(datum.getTime()-d4j.getTime())/6048e5+wt4j/7); // Anm.
4
}
Aufgerufen wird diese Berechnung z.B. so:
kw1=kalenderwoche(new Date(2000,0,2)); // 2. Januar 2000
kw2=kalenderwoche(new Date()); // heute
Carsten, Deine Lösung ist sicherlich gut aber etwas aufwendig, finde ich.
Zumal möchte ich halt alles verstehen.
Hat jemand einen Kalender von 1997/1998 was jetzt stimmt?
>ich glaub jetzt ist die Verwirrung komplett!
Nein, ISO hat Recht und sonst nix und niemand.
>Carsten, Deine Lösung ist sicherlich gut aber etwas aufwendig, finde ich.
Was ist daran aufwenig? Das ein Testprogramm drumherum liegt? Das
einzige, was Du (oder Udo) brauchst, ist CalendarWeek.* Wenn Du dazu
Fragen hast, darfst Du die ausnahmsweise mal per Mail stellen, da ich
meinen Source hier nicht oeffentlich ausdiskutieren mag. Zugegebener
Massen ist der Java-Algorythmus sehr nett und *kompakt*, aber den
versteht man auch nicht ohne nachdenken. ;)
Ich bin allerdings gerade am ueberlegen, ob ich mit dem (> 52) nicht
einen Bug drin habe, nur fehlt mir die Zeit, das wirklich zu verfolgen.
>Zumal möchte ich halt alles verstehen.
Niemand hindert Dich...
>Hat jemand einen Kalender von 1997/1998 was jetzt stimmt?
Sogar Oulook 2000 gibt mir Recht, also ist's wohl korrekt.
<wasredichdennda>
Hallo Alex -
Deine Tests haben ein Problem (Fehler?) mit Visual C++ aufgedeckt!
Zunächst aber die DIN-Vorschrift:
DIN-Nr.: EN 28601
Titel: Datenelemente und Austauschformate
Informationsaustausch
Darstellung von Datum und Uhrzeit
(ISO 8601, 1. Ausgabe 1988, Technical Corrigendum 1:1991)
Nun zur Berechnung der Kalenderwoche:
1) Die Kalenderwoche berechnet mittels
CTime t2( 1997, 12, 31, 0, 0, 0 ); // Jahr, Monat, Tag
CString sDatum = t2.Format("Kalenderwoche: %W, Tag: %w");
liefert auf jeden Fall eine falsche Kalenderwoche für Deine
Daten, den 31.12.1997 und den 1.1.1998 - nämlich
fälschlich die 52. Woche des Jahres 1997 statt
korrekt die 1. Woche des Jahres 1998,
da der 1.1.1998 ein Donnerstag ist.
(s. DIN-Vorschrift; oder in einem deutschen Kalender mit
Kalenderwochenangabe)
2) Die Kalenderwoche berechnet mittels meiner Routine
KalenderWoche( CTime t )
führt zu zwei verschiedenen Ergebnissen, je nachdem wie die
CTime-Variable t definiert wurde:
Wird t aus dem DateTimePicker-Steuerelement als CTime-Variable
(mittels Klassenassistent als Member-Variable) definiert, so
liefert KalenderWoche(t) das korrekte Ergebnis:
1. Woche des Jahres 1998.
Wird t mittels
CTime t( 1997, 12, 31, 0, 0, 0 );
definiert, so liefert KalenderWoche(t) das falsche Ergebnis:
53. Woche des Jahres 1998.
3) Die Kalenderwoche berechnet mittels meiner Routine
KalenderWoche( CTime t )
führt zum korrekten Ergebnis
KalenderWoche( t ) = 1,
wenn bei der Definition der CTime-Variablen nicht der
"pathologische" Zeitpunkt (00:00:00Uhr!) gewählt wird,
sondern mindestens 1 Stunde addiert wird:
CTime t( 1997, 12, 31, 1, 0, 0 );
Die "Format"-Methode liefert aber weiterhin das falsche Ergebnis
{"Kalenderwoche: 52, Tag: 3"}
4) Einige Erläuterungen sind noch wichtig:
Es genügt merkwürdigerweise nicht, nur Minuten oder gar nur
Sekunden hinzuzufügen; es muß mindestens 1 Stunde sein. Dann
arbeitet meine Routine aber offenbar richtig.
Das korrekte Arbeiten meiner Routine beruht möglicherweise
darauf, daß
CTime t( 1997, 12, 31, 0, 0, 0 );
den Zeitpunkt des Wechsels vom 31.12.1997 zum 1.1.1998 um
00:00:00Uhr für die von mir in KalenderWoche(t) verwendeten
Befehle
tm * tGMT = tDo.GetGmtTm( ); //Konvertiert "CTime" in Struktur
int TagNr = tGMT->tm_yday + 1; //Tag-Nr. im Jahr (ab 1 = 1.Jan.)
darstellen könnte (Microsoft-Programmierungs-Fehler?). Denn
wird die 1 Stunde nicht addiert, liefert tGMT->tm_yday den Wert 364;
wird die 1 Stunde addiert, so liefert tGMT->tm_yday den Wert 0 !
Eine letzte Bemerkung: Ich hatte meine Routine bisher nur mit der
CTime-Variablen dtPicker verwendet, die vom DateTimePicker-
Steuerelement geliefert wurde. Diese Variable dtPicker erhält
beim Klick im zugehörigen Kalender aber einen etwas unsinnigen
Wert. Er setzt sich aus dem Datum ( 1997, 12, 31, 0, 0, 0 ) _und_
der Tageszeit, zu der ich klicke (!), zusammen (Eine Microsoft-
Merkwürdigkeit)! Da heute der 8.3.2001 ist, macht das ja nun
wirklich keinen Sinn.
Diese Addition der aktuellen Tageszeit hat dann aber denselben
Effekt, als ob ich ( 1997, 12, 31, 1, 0, 0 ) angegeben hätte
(mit der einen zusätzlichen Stunde). Es sind dann ja schon ein
paar Stunden addiert worden. Meine Routine funktioniert also dann
nicht, wenn man nachts zwischen 0 und 1 Uhr im DateTimePicker-
Kalender klickt, da mindestens 1 Stunde nötig ist.
Sehr merkwürdige Reaktion dieses Steuerelements!
Ich weiß, dieser Beitrag ist lang, aber es mußte alles erklärt
werden.
Gruß Udo
Hallo -
um Carsten noch Konkurrenz zu machen, ;-))
hier die korrigierte Version meiner Routine, die hoffentlich
jetzt keinen Fehler mehr hat. Sie liefert als Kalenderwoche
korrekt =1 für
CTime t2( 1997, 12, 31, 0, 0, 0 ); // Jahr, Monat, Tag
------------
int KalenderWoche( CTime ct )
{
// DIN wird verwendet
int WochenTag = ct.GetDayOfWeek() - 1; //Montag soll =1 sein
if( WochenTag == 0 ) WochenTag = 7; // und Sonntag soll =7 sein
//Normung auf den Donnerstag der zugehörigen Woche.
// Dieser Donnerstag kann in einem anderen Jahr liegen:
CTimeSpan ts( 4-WochenTag,0,0,0 );
CTimeSpan ts1( 0,1,0,0 );
CTime tDo = ct + ts;
if( ct.GetHour() == 0 )
tDo = tDo + ts1;
tm * tGMT = tDo.GetGmtTm( ); //Konvertiert "CTime" in Struktur
int TagNr = tGMT->tm_yday + 1; //Tag-Nr. im Jahr (ab 1 = 1.Jan.)
int KW = TagNr / 7;
int Do1 = TagNr - KW*7;
//Do1 > 0: Do1 = Tag-Nr. des 1. Don. in dem Jahr
//Do1 = 0: Der 1. Jan. ist ein Donnerstag;
// dann stimmt die Wocheanzahl schon.
if( Do1 > 0 ) KW += 1; //Wenn Rest > 0: noch eine Kalenderwoche dazu!
return KW;
}
-------------
Gruß Udo
Hallo Carsten -
leider ist - ich kann mich natürlich täuschen - doch ein
Bug in Deiner Routine: Die Wochen-Nummer 53 ist möglich, und
sie tritt z. B. für das Datum 31.12.1992 auf.
Das gibt bei Dir fälschlich die Kalendewoche =1. ;-((
(Wehe, wenn ich mich jetzt geirrt habe.)
Gruß Udo
>leider ist - ich kann mich natürlich täuschen - doch ein
>Bug in Deiner Routine: Die Wochen-Nummer 53 ist möglich, und
>sie tritt z. B. für das Datum 31.12.1992 auf.
Genau den meinte ich eigentlich. Liegt natuerlich ein if drueber. Ich
glaube, der corrections Block muesste wie folgt lauten:
// correction
if (wCalendarWeek == 0)
{
wCalendarWeek= 53;
wYear--;
}
// Rest geloescht.
Aber das ist jetzt nur geraten, ungetestet und damit keine
Softwareentwicklung mehr, daher ein flup2poster. Auf jeden Fall Danke
fuer den Tip...
>(Wehe, wenn ich mich jetzt geirrt habe.)
Selbst wenn, lieber einen potentiellen Bug zweimal gecheckt und freuen,
dass es keiner war, als einen ubersehen...
flup2poster
Nun ich habe auch noch eine Routine zu bieten:
int GetWeekOfYear(COleDateTime datetime)
{
// Datum entschlüsseln
int year = datetime.GetYear();
// errechne Wochentag des 1.1
COleDateTime date_first_january(year,1,1,0,0,0);
// dayOfWeek 0==Montag, 1==Dienstag, ...
int day_of_week = (date_first_january.GetDayOfWeek()+5)%7;
/* Da das Jahr mit jedem Wochentag beginnen kann aber eine
* Woche immer mit einem Montag beginnt, wird also der Wochentag
* vor errechnung der eigentlichen KW dazgeschlagen.
* Dadurch ist primär der 1.1. immer in der 1.KW!
* Ist der 1.1 ein Mo,Di,Mi,Do dann beginnt das Jahr ab diesem 1.1
* mit der KW=1, sonst erst eine Woche später, also werden bei
* diesen Wochentagen jeweils 1 addiert (wenn tag<=3 für Mo,Di,Mi,Do). */
int week_of_year =
(int)(((datetime-date_first_january).GetDays()+day_of_week) / 7) +
(day_of_week<=3 ? 1:0);
// Sonderfälle kontrollieren
if (week_of_year==0)
{
/* Sonderfall die 0. KW! Wir haben also einen Tag unter erwischt der
* der 1.1, 2.1 oder 3.1 ist, wobei der 1.1. KEIN Mo, Di, Mi, Do ist.
* Die 1. KW fängt also nicht mit dem 1.1 an.
* Wir errechnen also einfach die KW relativ zum 1.1 des Vorjahres
*------------------------------------------------------------------*/
COleDateTime date_first_january(year-1,1,1,0,0,0);
day_of_week = (date_first_january.GetDayOfWeek()+5)%7;
/* und es wird genauso korrigiert wie eben, nur das Ergebnis ist
* jetzt nicht die KW=0 sondern KW=52 oder KW=53 */
week_of_year =
(int)(((datetime-date_first_january).GetDays()+day_of_week) / 7) +
(day_of_week<=3 ? 1:0);
}
else if (week_of_year==53)
{
/* Sonderfall die KW=53, wir haben also entweder die richtige
* 53. KW erwischt oder bereits die 1. KW des nächsten Jahres.
* Ist der 1.1.(jahr+1) also ein Mo, Di, Mi, Fr dann haben wir
* tatsächlich schon die KW=1, sonst die 53. KW!
*------------------------------------------------------------------*/
COleDateTime date_first_january(year+1,1,1,0,0,0);
day_of_week = (date_first_january.GetDayOfWeek()+5)%7;
/* 1.1 bereits die KW=1 oder KW=53 */
week_of_year = day_of_week<=3 ? 1:53;
}
// und nun das Ergebnis zurück
return week_of_year;
}
Diese liefert die folgenden Ergebnisse:
Mo 31.12.1979 1 Di 01.01.1980 1
Mi 31.12.1980 1 Do 01.01.1981 1
Do 31.12.1981 53 Fr 01.01.1982 53
Fr 31.12.1982 52 Sa 01.01.1983 52
Sa 31.12.1983 52 So 01.01.1984 52
Mo 31.12.1984 1 Di 01.01.1985 1
Di 31.12.1985 1 Mi 01.01.1986 1
Mi 31.12.1986 1 Do 01.01.1987 1
Do 31.12.1987 53 Fr 01.01.1988 53
Sa 31.12.1988 52 So 01.01.1989 52
So 31.12.1989 52 Mo 01.01.1990 1
Mo 31.12.1990 1 Di 01.01.1991 1
Di 31.12.1991 1 Mi 01.01.1992 1
Do 31.12.1992 53 Fr 01.01.1993 53
Fr 31.12.1993 52 Sa 01.01.1994 52
Sa 31.12.1994 52 So 01.01.1995 52
So 31.12.1995 52 Mo 01.01.1996 1
Di 31.12.1996 1 Mi 01.01.1997 1
Mi 31.12.1997 1 Do 01.01.1998 1
Do 31.12.1998 53 Fr 01.01.1999 53
Fr 31.12.1999 52 Sa 01.01.2000 52
So 31.12.2000 52 Mo 01.01.2001 1
Mo 31.12.2001 1 Di 01.01.2002 1
Di 31.12.2002 1 Mi 01.01.2003 1
Mi 31.12.2003 1 Do 01.01.2004 1
--
Martin Richter [MVP] WWJD
"In C we had to code our own bugs. In C++ we can inherit them."
FAQ,s : http://mfcfaq.stingray.com/ http://vcfaq.albert-weinert.de
Samples: http://codeguru.developer.com http://www.codeproject.com
Hallo Martin -
ist ja lustig, wie die guten Programme so aus ihren Löchern
kriechen (wobei ich meins natürlich mit einbeziehe ;-))) ).
Ansonsten, danke.
Gruß Udo
ja jetzt können wir uns aussuchen, welches uns am besten zusagt.
Danke.
Gruss
Alex