Timestamp vom Anfang der Woche/des Monats?
WauWau
- php
Hallo,
das Problem ist eigentlich ganz simpel, aber ich habe eigentlich nach einer netten kompakten Lösung gesucht, die ich weder im PHP-Manual noch online bei http://www.php.net (da gibt es ja die tollen comments bei der doku) gefunden habe.
Also, ich habe ein süßes kleines Newssystem, da sind News gespeichert (was auch sonst). In einer MySQL-Tabelle. Und ihr Datum ist per PHP-Timestamp gespeichert. naja, wie dem auch sei, auf jeden fall habe ich dann da ein Seitchen, da kann man dann auswählen, ob man (a) nur die neusten News angezeigt bekommen möchte (b) alle News dieser Woche angezeigt bekommen möchte (c) alle News vom Monat angezeigt bekommen möchte.
Ist auch sofern kein Problem, beispielsweise habe ich jetzt mal als Richtwert für die "neusten" News einen Timestamp von Heute-7 Tage, und dann wird eben ein MySQL-Query abgeschickt...:
mysql_query("SELECT * FROM news WHERE date > $last_time ORDER BY date DESC LIMIT 8")...
und $last_time ist eben dann der Timestamp heute-7 Tage.
So, nun zu (b) und (c), hier fängt nämlich das Problemchen an. Höchstwahrscheinlich wird es gar keins geben, nur ich bin zu strunz zum denken, aber wie dem auch sei, vielleicht kann sich ja jemand ein paar sekündchen entbehren ... und einfach mal was nettes tippen :)
Also, wie bekomme ich den Timestamp vom in diesem Fall 5.4.2004, 0:0:0 Uhr? Also dem ersten Tag der Woche? Und zu (b) eben in diesem Fall der 1.4.2004, 0:0:0 Uhr? - dem ersten Tag vom Monat?
Vielen Dank :]
WauWau
Moin!
Schau Dir mal date() und mktime() an.
date kann Dir den Monat und das Jahr liefern, sowie die zahl des aktuellen Wochentages und natürlich den Tag des Monats.
mktime kann auch sowas wie mktime(0,0,0,4,7-4,2004) # (Stunde,Minute,Sekunde,Monat,Tag,Jahr)
selbst ein mktime(0,0,0,4,2-4,2004) sollte es tun (falls der zweite mal ein Donnerstag ist.
Die rückgaben von mktime() jagst durch date() und bekommst, was immer Du willst.
MFFG (Mit freundlich- friedfertigem Grinsen)
fastix®
Hallo fastix®,
Schau Dir mal date() und mktime() an.
kenne ich mittlerweile bestens auswendig. Aber ich dachte nicht an ein rumgerechne mit verschachteltem.... mktime(0,0,0,x,date("...",...)+-alsdaksd) usw... dachte es ginge auch einfacher...
date kann Dir den Monat und das Jahr liefern, sowie die zahl des aktuellen Wochentages und natürlich den Tag des Monats.
jo.
mktime kann auch sowas wie mktime(0,0,0,4,7-4,2004) # (Stunde,Minute,Sekunde,Monat,Tag,Jahr)
selbst ein mktime(0,0,0,4,2-4,2004) sollte es tun (falls der zweite mal ein Donnerstag ist.
Ich habe keine Ahnung, wie du auf "7-4" bzw. "2-4" kommst. Auf jeden Fall liefert erstes den Timestamp von 0 uhr am 03.04.2004, und mit dem kann ich nun gar nix anfangen [die woche hat afaik am 05.04. begonnen, aber vielleicht ... sehe ich auch was falsch ;-)].
Und mit dem Zweiten bekomme ich den timestamp genauso um 0 uhr vom 30.03.2004...!? Was willst du damit bezwecken?
Die rückgaben von mktime() jagst durch date() und bekommst, was immer Du willst.
Mir ist klar, dass mktime() einen Timestamp liefert.
WauWau
Moin!
selbst ein mktime(0,0,0,4,2-4,2004) sollte es tun (falls der zweite mal ein Donnerstag ist.
Und mit dem Zweiten bekomme ich den timestamp genauso um 0 uhr vom 30.03.2004...!? Was willst du damit bezwecken?
Donnerstag: -> Tag der Woche = 4
date("d.m.Y",mktime(0,0,0,4,2-4,2004) liefert den 30.03.2004... ist doch richtig:
30.03. -> Mo
31.03. -> Di
01.04. -> Mi
02.04. -> Do
[1] Du subtrahierst den aktuellen Wochentag vom aktuellen Tag des Monats und jagst das durch mktime()., dann durch date() Heraus kommt der Wochenbeginn.
[2] Du lässt Dir gleich von date("01.m.Y") (oder wie auch immer) ausgeben und bekommst den Monatsbeginn.
MFFG (Mit freundlich- friedfertigem Grinsen)
fastix®
Hallo fastix®,
Donnerstag: -> Tag der Woche = 4
stimmt, heute ist ja schon Donnerstag! Aber bei mir ist heute der 08.04.2004. Mein Kalender übrigens:
+-------+---------+------------------------+
| 29.03 | Montag | LETZTE WOCHE |
| 30.03 | DI | |
| 31.03 | MI | |
| 01.04 | DO | |
| 02.04 | FR | |
| 03.04 | SA | |
| 04.04 | SO | (der 04.04.04!) |
+-------+---------+------------------------+
| 05.04 | MO | DIESE WOCHE |
| 06.04 | DI | |
| 07.04 | MI | |
| 08.04 | DO | >>>HEUTE |
| 09.04 | FR | |
| 10.04 | SA | |
| 11.04 | SO | |
+-------+---------+------------------------+
Die Woche hat bei mir am 05.04. angefangen, mein Monat hat am 01.04. angefangen.
date("d.m.Y",mktime(0,0,0,4,2-4,2004) liefert den 30.03.2004... ist doch richtig:
30.03. -> Mo
bei mir ist es ein DI, siehe Kalender
31.03. -> Di
Der ist bei mir ein MI, siehe Kalender
01.04. -> Mi
...und das ist hier bei mir in Deutschland ein DO, siehe Kalender
02.04. -> Do
glücklicherweise war damals bei mir schon Freitag, siehe Kalender.
[1] Du subtrahierst den aktuellen Wochentag vom aktuellen Tag des Monats und jagst das durch mktime()., dann durch date() Heraus kommt der Wochenbeginn.
aktueller Wochentag = 4
aktueller Monatstag = 7
stimmt, plötzlich machts *kling* ... was ist denn mit mir los!? *verwirrt* irgendwie scheint mein Comp da oben auf underclocking eingestellt.... bekommt vielleicht zu wenig strom!? MAn weiß es nie ;-)
[2] Du lässt Dir gleich von date("01.m.Y") (oder wie auch immer) ausgeben und bekommst den Monatsbeginn.
Und den dann durch strtotime() jagen? Das wäre auch eine Idee... Naja, wenn ichs mir recht überlege, ist der Monatsbeginn ja kein Problem:
mktime(0,0,0,1,date("m"),date("Y"));
keine Ahnung weswegen ich da auch noch nicht früher drauf gekommen bin...
Ok, also den Wochenbeginn bekomme ich mit
mktime(0,0,0,date("j")-date("w"),date("m"),date("Y"));
raus. Wunderbar, ich habe doch gesagt, höchstwahrscheinlich denkt WauWau mal wieder nicht mit ....
WauWau
Moin!
mktime(0,0,0,1,date("m"),date("Y"));
mktime(0,0,0,date("j")-date("w"),date("m"),date("Y"));
Das war es, wo ich Dich hinschubsen wollte. Den Donnerstag für den 2.4.2004 hatte ich "festgelegt" um zu zeigen: das geht sogar mit negativen Zahlen...
Und sei ehrlich: sieht doch sogar "elegant" aus oder?
MFFG (Mit freundlich- friedfertigem Grinsen)
fastix®
Hallo fastix®,
mktime(0,0,0,1,date("m"),date("Y"));
mktime(0,0,0,date("j")-date("w"),date("m"),date("Y"));
Das war es, wo ich Dich hinschubsen wollte. Den Donnerstag für den 2.4.2004 hatte ich "festgelegt" um zu zeigen: das geht sogar mit negativen Zahlen...
aja... ok, dass es mit negativen zahlen geht, dem war ich mir auch bewusst, immerhin bin ich ja ein aufrichtiger manual-leser ;) - nur irgendwie ist's heute nacht nichts wahres... obwohl ich noch unbedingt mein News-System endlich fertigbekommen wollte!!! Ich werde mich am besten mal gleich aus dem staub machen (Die zwei zeilen da oben nehme ich mit ;)), und mich an die Arbeit machen :)
Und sei ehrlich: sieht doch sogar "elegant" aus oder?
jo, so ein bisschen schon <g> ;-)
WauWau
Hola,
Rein zur Info, dasda ist total falsch:
mktime(0,0,0,1,date("m"),date("Y"));
das würde z.B. heute einen Timestamp vom 04.01.2004 zurückliefern
mktime(0,0,0,date("j")-date("w"),date("m"),date("Y"));
und das einen vom 04.05.2004...
@fastix(c): Auch nicht so richtig bei der Sache gewesen, nicht wahr ;)... naja, ist ja nicht schlimm... So ist es jedenfalls richtig:
Diese Woche: mktime(0,0,0,date("m"),date("j")-date("w"),date("Y"));
Dieser Monat: mktime(0,0,0,date("m"),1,date("Y")));
eingebaut in meine News-Klasse sieht das dann so aus:
function fast_last($last_time=false, $connect=false) {
$timestamps = array(
'latest' => mktime(0, 0, 0, date("m"), date ("d")-7, date("Y")), // letzte 7 Tage
'thisweek' => mktime(0,0,0,date("m"),date("j")-date("w"),date("Y")), // diese Woche
'thismonth' => mktime(0,0,0,date("m"),1,date("Y"))); // dieser Monat
$time = ($last_time ? (is_numeric($last_time) ? $last_time : (isset($timestamps[$last_time]) ? $timestamps[$last_time] : $timestamps['latest'])) : $timestamps['latest']);
if($connect) $this->db_connect();
$n = mysql_query("SELECT * FROM news WHERE date > $time ORDER BY date DESC LIMIT 8") or $this->db_error();
$r = '';
while($d = mysql_fetch_assoc($n)) {
$r .= $this->news(stripslashes($d["id"]), stripslashes($d["head"]),
stripslashes($d["date"]), stripslashes($d["image"]),
stripslashes($d["body"]), "more"); }
return (strlen($r) == '' ? '[KEINE NEUEN NEWS] [TIMESTAMP]: '.$time : $r);
}
oh und schau mal einer an, da habe ich gleich noch einen bug entdeckt: Was soll den das "LIMIT 8" bei meinem Query... ;) ? Muss ich gleich mal wegmachen...
WauWau
Hallo WauWau,
schön dass du dir nochmal antwortest, aber das musstest du ja jetzt einfach mal rein des "Postingthemas" wegen machen - du hast nämlich diesem Posting hier [pref:t=78175&m=451860] kein anderes Thema, wie du es doch geplant hast, gegeben. Schäm' dich was, du böser Hund. Morgen gibt's kein Sticki *g* *scnr* ;)
oh und schau mal einer an, da habe ich gleich noch einen bug entdeckt: Was soll den das "LIMIT 8" bei meinem Query... ;) ? Muss ich gleich mal wegmachen...
Genau, so ist die Methode richtig:
function fast_last($last_time=false, $connect=false) {
$timestamps = array(
'latest' => mktime(0, 0, 0, date("m"), date ("d")-7, date("Y")), // letzte 7 Tage
'thisweek' => mktime(0,0,0,date("m"),date("j")-date("w"),date("Y")), // diese Woche
'thismonth' => mktime(0,0,0,date("m"),1,date("Y"))); // dieser Monat
$time = ($last_time ? (is_numeric($last_time) ? $last_time : (isset($timestamps[$last_time]) ? $timestamps[$last_time] : $timestamps['latest'])) : $timestamps['latest']);
if($connect) $this->db_connect();
$n = mysql_query("SELECT * FROM news WHERE date > $time ORDER BY date DESC") or $this->db_error();
if(mysql_num_rows($n)==0 && !$last_time) {
$n = mysql_query("SELECT * FROM news ORDER BY date DESC LIMIT 8") or $this->db_error();
}
$r = '';
while($d = mysql_fetch_assoc($n)) {
$r .= $this->news(stripslashes($d["id"]), stripslashes($d["head"]),
stripslashes($d["date"]), stripslashes($d["image"]),
stripslashes($d["body"]), "more"); }
return (!strlen($r) ? '[NONE]' : $r);
}
Wenn der erste Parameter dann sogar noch false war, wie er es beim Portal sein wird, dann werden - sofern keine News in den letzten Tagen gespeichert wurden, einfach die 8 letzten News ausgegeben. Aber ich könnte es sogar noch ein bisschen verändern: Ich könnte in der Zeile if(mysql_num_rows($n)==0...) schreiben: if(mysql_num_rows($n)<=2). Das würde es nämlich wesentlich besser treffen...
Aber ich werde jetzt mal nicht jeden Quatsch, der sowieso keinen interressiert, hier posten :)
WauWau
Moin!
Schau Dir mal date() und mktime() an.
Ich finde es spannend, dass bei Datumsrechnerei jeder sofort an irgendwelche komplexen Rechnereien in PHP denkt, aber niemand die Datumsrechnungsfunktionen von MySQL berücksichtigt.
Zuerst einmal: Diese Funktionen sind am wirkungsvollsten, wenn man in MySQL keinen Unix-Timestamp in ein Integerfeld speichert, sondern eine Spalte vom typ DATETIME (wenn man die Uhrzeit benötigt) oder DATE anlegt.
Und dann sind gewisse Operationen relativ simpel.
Vom aktuellen Datum nur Jahr und Monat nehmen, den Tag auf "01" setzen (Monatsanfang):
SELECT * FROM tab WHERE TO_DAYS(datumspalte) >= TO_DAYS(CONCAT(YEAR(NOW()),"-",MONTH(NOW()),"-01"))
Alternativ kann man natürlich auch in der datumsspalte nur auf Jahr und Monat vergleichen:
SELECT * FROM tab WHERE YEAR(datumspalte) = YEAR(NOW()) AND MONTH(datumspalte) = MONTH(NOW())
Zusammenfassen könnte man das auch, indem man datumspalte und NOW() als formatiertes Datum nur mit Jahr und Monat ausgibt und als String vergleicht. Ist die Frage, was performanter ist.
Die Geschichte mit dem Wochenanfang ließe sich mit DAYOFWEEK() und DATE_SUB() bzw. DATE_ADD() regeln - also die Differenz des DAYOFWEEK() des aktuellen Tages zum Montag oder Sonntag (1 oder 2) errechnen und von aktuellen Datum abziehen.
Alternativ wieder eine elegantere Lösung:
SELECT * FROM tab WHERE YEARWEEK(datumspalte) = YEARWEEK(NOW())
- Sven Rautenberg
Hallo Sven,
Ich finde es spannend, dass bei Datumsrechnerei jeder sofort an irgendwelche komplexen Rechnereien in PHP denkt, aber niemand die Datumsrechnungsfunktionen von MySQL berücksichtigt.
na gut, das ganze mit MySQL zu machen, wäre auch eine Idee. Aber erstens mal wird es letztenendes nicht wirklich einfacher, und zweitens ... gefallen mir die "Date"-Felder von MySQL nicht wirklich. Die sind irgendwie hässlich, diese Speicherungsteile, und dementsprechend - was liegt näher als einfach simpel einen PHP-Timestamp (meinetwegen auch "Unix-Timestamp") zu speichern, mit dem man dann in PHP ganz gemütlich rumbasteln kann, als irgendwelche mühseligen Umwandlungsfunktionen MySQL-"Timestamp"<=>Unix-Timestamp (auf dem Online-Manual bei php.net haben einige Leute was ganz brauchbares gepostet...) jedes mal auszuführen...
Ich meine, wo ist der Unterschied, ob ich eine MySQL-Abfrage etwa so mache:...
"SELECT * FROM news WHERE date > $x ORDER BY date DESC, id"
und $x ist hierbei ein simpler PHP-Timestamp von gestern (ist in diesem Zusammenhang irrelevant)... oder wenn ich so was schreibe wie
"SELECT * FROM news WHERE TO_DAYS(date) >= ... "
und dabei dann irgendwelche speziellen mySQL-Funktionen benutze. Mein Syntax oben hat zum einen den Vorteil, dass ich ganz simpel einfach für $x irgendeinen Timestamp einsetzten kann, wobei ich bei irgendwelchen mySQL-Funktionen mir erst mal den MySQL-Syntax zusammenbasteln darf.
Ach ja, und zudem möchte ich meinen Abfragesyntax eigentlich auch noch kompatibel halten, also ich meine, es könnte ja vorkommen, dass ich urplötzlich auf ODBC oder sowas angewiesen bin (obwohl das afaik auch so eine art SQL-Syntax benutzt, aber ... keine ahnung).
Zuerst einmal: Diese Funktionen sind am wirkungsvollsten, wenn man in MySQL keinen Unix-Timestamp in ein Integerfeld speichert, sondern eine Spalte vom typ DATETIME (wenn man die Uhrzeit benötigt) oder DATE anlegt.
Hmm, und dann nochmal vom ganz theoretischen angesehen... Ein Unix-Timestamp, der 11 Ziffern beinhaltet (also ein normaler "INT"), nimmt doch weiniger speicher weg als "YYYYMMDDHHMMSS", also 14 Zeichen des Types "INT" oder meinetwegen auch "DATE"....
Und dann sind gewisse Operationen relativ simpel.
Vergleichen wir mal:
SELECT * FROM tab WHERE TO_DAYS(datumspalte) >= TO_DAYS(CONCAT(YEAR(NOW()),"-",MONTH(NOW()),"-01"))
"SELECT * FROM news WHERE date > ".mktime(0,0,0,date("m"),date("j")-date("w"),date("Y"));
und, was ist letztenendes "einfacher"? Hmmm, ich finde mein Beispielchen übersichtlicher, da man sofort erkennt, welchen Timestamp mktime() zurückliefert [afaik mktime(sec,min,stund,monat,tag,jahr,sommer/winter)], und keine komischen MySQL-Funktionen anwendet.
SELECT * FROM tab WHERE YEAR(datumspalte) = YEAR(NOW()) AND MONTH(datumspalte) = MONTH(NOW())
ok, sooo kompliziert sieht es nicht aus, aber irgendwie gefällt mir meine Lösung besser (->[pref:t=78175&m=451870])...
Zusammenfassen könnte man das auch, indem man datumspalte und NOW() als formatiertes Datum nur mit Jahr und Monat ausgibt und als String vergleicht. Ist die Frage, was performanter ist.
hmm, ja, ist auch die Frage, ob PHP das mit seinen Timestamps nicht auch recht schnell hinbekommt... Also ob diese MySQL-Funktionen oben, wo doch MySQL mit strings und sowas rumhantieren müssen, letztenendes mit sowas "SELECT * FROM tab WHERE datumspalte < 12345678901 AND datumsspalte > 12345678900" vergleichbar ist.
Die Geschichte mit dem Wochenanfang ließe sich mit DAYOFWEEK() und DATE_SUB() bzw. DATE_ADD() regeln - also die Differenz des DAYOFWEEK() des aktuellen Tages zum Montag oder Sonntag (1 oder 2) errechnen und von aktuellen Datum abziehen.
also letztenendes auch wieder gerechne. Welches Programm dieses Gerechne anstellt, spielt doch keine wirklich große rolle, oder?
WauWau