2009-05-29 4 views
10

Sto cercando di scrivere una funzione di calendario come questoottenere il primo o il Venerdì scorso in un mese

function get_date($month, $year, $week, $day, $direction) 
{ 
    .... 
} 

$week è un numero intero (1, 2, 3 ...), $ al giorno è un giorno (dom, lun, ...) o numero, a seconda di quale sia più facile. La direzione è un po 'confusa, perché fa un calcolo diverso.

Per un esempio, chiamiamolo

get_date(5, 2009, 1, 'Sun', 'forward');

Esso utilizza il default, e ottiene la prima Domenica di Maggio cioè 2009-05-03. Se chiamiamo

get_date(5, 2009, 2, 'Sun', 'backward');

, restituisce la seconda Domenica scorsa maggio cioè 2009-05-24.

+0

Solo per curiosità .. A cosa stai usando ?! Non è così semplice, ma può essere fatto comunque. – MartinodF

+0

Sto scrivendo un job scheduler. Alcune delle posizioni sono mensili e devo essere in grado di determinare quali date mostrarle nel calendario. – Zahymaka

+0

Scriverlo per te, spero che funzioni come ti aspettavi! – MartinodF

risposta

12

Forse può essere reso più veloce ...
Questo è stato MOLTO interessante da codificare.

prega di notare che è $direction 1 per avanti e -1 per all'indietro per facilitare le cose :)
Inoltre, $day inizia con un valore pari a 1 per Lunedi e termina al 7 per Domenica.

function get_date($month, $year, $week, $day, $direction) { 
    if($direction > 0) 
    $startday = 1; 
    else 
    $startday = date('t', mktime(0, 0, 0, $month, 1, $year)); 

    $start = mktime(0, 0, 0, $month, $startday, $year); 
    $weekday = date('N', $start); 

    if($direction * $day >= $direction * $weekday) 
    $offset = -$direction * 7; 
    else 
    $offset = 0; 

    $offset += $direction * ($week * 7) + ($day - $weekday); 
    return mktime(0, 0, 0, $month, $startday + $offset, $year); 
} 

ho provato con alcuni esempi e sembra funzionare sempre, assicurati di controllare due volte, però;)

+0

Oh e anche notare che lunedì = 1, domenica = 7 – MartinodF

2

È possibile utilizzare mktime per recuperare il timestamp unix del primo giorno del mese:

$firstOfMonth = mktime(0, 0, 0, $month, 1, $year); 

Quando si ha la data del primo giorno di un certo mese è facile recuperare il giorno della settimana per quella data utilizzando date:

$weekday = date("N", $firstOfMonth); 

da lì è piuttosto facile da appena un passo in avanti per ottenere la data che stai cercando.

20

La versione in lingua-agnostic:

per ottenere il primo giorno particolare del mese, iniziamo con il primo giorno del mese: YYYY-MM-01. Usa qualsiasi funzione disponibile per dare un numero corrispondente al giorno della settimana. Sottrai quel numero dal giorno che stai cercando; per esempio, se il primo giorno del mese è mercoledì (2) e stai cercando il venerdì (4), sottrai 2 da 4, lasciando 2. Se la risposta è negativa, aggiungi 7. Infine aggiungila alla prima di il mese; per il mio esempio, il primo venerdì sarebbe il 3 °.

Per ottenere l'ultimo venerdì del mese, trovare il primo venerdì del mese successivo e sottrarre 7 giorni.

0

Basta scoprire qual è il primo e l'ultimo giorno del mese in questione (vale a dire il 1 maggio 2009 è un venerdì e il 31 maggio 2009 è una domenica) Credo che la maggior parte delle funzioni PHP utilizzi lunedì = 0, domenica = 6 quindi venerdì = 4, quindi sai che domenica (6) - venerdì (4) = 2, quindi 31-2 = 29, cioè l'ultimo venerdì di questo mese è il 29. Per il primo venerdì, se il numero è negativo, aggiungere 7, se il numero è 0, il mese inizia il venerdì.

8

strtotime() può aiutare. per esempio.

<?php 
$tsFirst = strtotime('2009-04-00 next friday'); 
$tsLast = strtotime('2009-05-01 last friday'); 
echo date(DATE_RFC850, $tsFirst), " | ", date(DATE_RFC850, $tsLast);
stampe
Friday, 03-Apr-09 00:00:00 CEST | Friday, 24-Apr-09 00:00:00 CEST

+0

Ho già controllato, non supporta "penultimo" o simili, ed è molto più lento. – MartinodF

6

Non c'è bisogno di calcoli o loop - questo è molto facile da fare con strtotime():

Trova l'all'ennesima o ultima occorrenza di un particolare giorno di un determinato mese:

///////////////////////////////////////////////////////////////// 
// Quick Code 
///////////////////////////////////////////////////////////////// 

// Convenience mapping. 
$Names = array(0=>"Sun", 1=>"Mon", 2=>"Tue", 3=>"Wed", 4=>"Thu", 5=>"Fri", 6=>"Sat"); 

// Specify what we want 
// In this example, the Second Monday of Next March 
$tsInMonth = strtotime('March'); 
$Day = 1; 
$Ord = 2; 

// The actual calculations 
$ThisMonthTS = strtotime(date("Y-m-01", $tsInMonth)); 
$NextMonthTS = strtotime(date("Y-m-01", strtotime("next month", $tsInMonth))); 
$DateOfInterest = (-1 == $Ord) 
    ? strtotime("last ".$Names[$Day], $NextMonthTS) 
    : strtotime($Names[$Day]." + ".($Ord-1)." weeks", $ThisMonthTS); 


///////////////////////////////////////////////////////////////// 
// Explanation 
///////////////////////////////////////////////////////////////// 

// Specify the month of which we are interested. 
// You can use any timestamp inside that month, I'm using strtotime for convenience. 
$tsInMonth = strtotime('March'); 

// The day of interest, ie: Friday. 
// It can be 0=Sunday through 6=Saturday (Like 'w' from date()). 
$Day = 5; 

// The occurrence of this day in which we are interested. 
// It can be 1, 2, 3, 4 for the first, second, third, and fourth occurrence of the day in question in the month in question. 
// You can also use -1 to fine the LAST occurrence. That will return the fifth occurrence if there is one, else the 4th. 
$Ord = 3; 

//////////////////////////////////////////////////////////////// 
// We now have all the specific values we need. 
// The example values above specify the 3rd friday of next march 
//////////////////////////////////////////////////////////////// 

// We need the day name that corresponds with our day number to pass to strtotime(). 
// This isn't really necessary = we could just specify the string in the first place, but for date calcs, you are more likely to have the day number than the string itself, so this is convenient. 
$Names = array(0=>"Sun", 1=>"Mon", 2=>"Tue", 3=>"Wed", 4=>"Thu", 5=>"Fri", 6=>"Sat"); 

// Calculate the timestamp at midnight of the first of the month in question. 
// Remember $tsInMonth is any date in that month. 
$ThisMonthTS = strtotime(date("Y-m-01", $tsInMonth)); 

// Calculate the timestamp at midnight of the first of the FOLLOWING month. 
// This will be used if we specify -1 for last occurrence. 
$NextMonthTS = strtotime(date("Y-m-01", strtotime("next month", $tsInMonth))); 

// Now we just format the values a bit and pass them to strtotime(). 
// To find the 1,2,3,4th occurrence, we work from the first of the month forward. 
// For the last (-1) occurence,work we work back from the first occurrence of the following month. 
$DateOfInterest = (-1 == $Ord) ? 
    strtotime("last ".$Names[$Day], $NextMonthTS) : // The last occurrence of the day in this month. Calculated as "last dayname" from the first of next month, which will be the last one in this month. 
    strtotime($Names[$Day]." + ".($Ord-1)." weeks", $ThisMonthTS); // From the first of this month, move to "next dayname" which will be the first occurrence, and then move ahead a week for as many additional occurrences as you need. 
+0

Grazie mille – beardedlinuxgeek

+0

@beardedlinuxgeek - My Pleasure. – Eli

1
function get_date($month, $year, $week, $day) { 
    # $month, $year: current month to search in 
    # $week: 0=1st, 1=2nd, 2=3rd, 3=4th, -1=last 
    # $day: 0=mon, 1=tue, ..., 6=sun 

    $startday=1; $delta=0; 
    if ($week < 0) { 
     $startday = date('t', mktime(0, 0, 0, $month, 1, $year)); # 28..31 
     $delta=1; 
    } 
    $start = mktime(0, 0, 0, $month, $startday, $year); 
    $dstart = date('w', $start)-1; # last of the month falls on 0=mon,6=sun 
    $offset=$day-$dstart; if ($offset<$delta){$offset+=7;} 
    $newday=$startday+$offset+($week*7); 
    return mktime(0, 0, 0, $month, $newday, $year); 
} 

questo funziona per me, e basato sulla versione indipendente dal linguaggio :-) Solo troppo male, avevo bisogno di fare che il delta-cosa (perché se l'ultimo giorno di il mese è il giorno della settimana desiderato, non è necessario sottrarre 7)

5

Le funzioni di cronometraggio integrate di PHP lo rendono semplice.

http://php.net/manual/en/function.strtotime.php

// Get first Friday of next month. 
$timestamp = strtotime('first fri of next month'); 

// Get second to last Friday of the current month. 
$timestamp = strtotime('last fri of this month -7 days'); 

// Format a timestamp as a human-meaningful string. 
$formattedDate = date('F j, Y', strtotime('first wed of last month')); 

noti che abbiamo sempre voglia di fare in modo che abbiamo definito il fuso orario corretto per l'utilizzo con strtotime modo che PHP ha una comprensione di dove per calcolare il timestamp per rispetto a quello che il fuso orario la macchina pensa che sia in.

date_default_timezone_set('America/New_York'); 
$formattedDate = date('F j, Y', strtotime('first wed of last month +1 week')); 
4
echo date('Y-m-d',strtotime('last friday')); 
0

lo stesso può essere realizzato molto elegantemente utilizzando la classe DateTime.

$time_zone = new DateTimeZone('Europe/Ljubljana'); 

$first_friday_of_this_month = new DateTime('first Friday of this month', $time_zone); 
$last_friday_of_this_month = new DateTime('last Friday of this month', $time_zone); 

echo $first_friday_of_this_month->format('Y-m-d'); # 2015-11-06 
echo $last_friday_of_this_month->format('Y-m-d'); # 2015-11-27 
0

Questo sembra funzionare perfetto ogni volta; prende qualsiasi data fornita e restituisce la data dell'ultimo venerdì del mese, anche in caso di 5 venerdì del mese.

function get_last_friday_of_month($inDate) { 
    $inDate = date('Y-m-24', strtotime($inDate)); 
    $last_friday = date('Y-m-d',strtotime($inDate.' next friday')); 
    $next_friday = date('Y-m-d',strtotime($inDate.' next friday')); 

    if(date('m', strtotime($last_friday)) === date('m', strtotime($next_friday))){ 
     $last_friday = $next_friday; 
    }else{ 
     // 
    } 
    return $last_friday; 
} 
0

Di seguito è la soluzione più rapida ed è possibile utilizzare in tutte le condizioni. Inoltre potresti ottenere una serie di tutto il giorno della settimana se lo modifichi un po '.

function findDate($date, $week, $weekday){ 
    # $date is the date we are using to get the month and year which should be a datetime object 
    # $week can be: 0 for first, 1 for second, 2 for third, 3 for fourth and -1 for last 
    # $weekday can be: 1 for Monday, 2 for Tuesday, 3 for Wednesday, 4 for Thursday, 5 for Friday, 6 for Saturday and 7 for Sunday 

    $start = clone $date; 
    $finish = clone $date; 

    $start->modify('first day of this month'); 
    $finish->modify('last day of this month'); 
    $finish->modify('+1 day'); 

    $interval = DateInterval::createFromDateString('1 day'); 
    $period = new DatePeriod($start, $interval, $finish); 

    foreach($period AS $date){ 
     $result[$date->format('N')][] = $date; 
    } 

    if($week == -1) 
     return end($result[$weekday]); 
    else 
     return $result[$weekday][$week]; 
} 


$date = DateTime::createFromFormat('d/m/Y', '25/12/2016'); 

# find the third Wednesday in December 2016 
$result = findDate($date, 2, 3); 
echo $result->format('d/m/Y'); 

Spero che questo aiuti.

Fatemi sapere se avete bisogno di ulteriori informazioni.