Προς το περιεχόμενο

Πρόβλημα σε PHP με ημερομηνίες (biweekly και monthly) με βάση συγκεκριμένη ημερομηνία


philos

Προτεινόμενες αναρτήσεις

Δημοσ. (επεξεργασμένο)

Καλησπέρα!
Έχουμε την εξής class method για κάποια, ας τα πούμε Tasks:

    public function canAssignedToday()
    {
        // $day = η σημερινή ημέρα
        $day = strtolower(date('l'));
        if ($this->frequency == 'daily')
        {
            return true;
        }
        else if ($this->frequency == 'weekly')
        {
            if ($day == $this->frequency_option)
            {
                return true;
            }
        }
        else if ($this->frequency == 'biweekly')
        {
            // στο ??? πρέπει να μπει κάτι με το $this->date_added (unix time)
            if ($day == $this->frequency_option && ???)
            {
                return true;
            }
        }
        else if ($this->frequency == 'monthly')
        {
            // στο ??? πρέπει να μπει κάτι με το $this->date_added (unix time)
            if ($day == $this->frequency_option && ???)
            {
                return true;
            }            
        }

        return false;
    }

Έβαλα τον κώδικα γιατί οι γνώστες θα καταλάβετε αμέσως τι κάνει και τι θέλει να κάνει.
Ουσιαστικά έχω κολλήσει στο biweekly και στο monthly.
Το frequency_option παίρνει τιμές 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', που έχουν νόημα για frequency = weekly, biweekly και monthly.
Το date_added είναι μια unix time (ΟΧΙ της στιγμής που τρέχει το script! ) της στιγμής που ο διαχειριστής πρόσθεσε το Task.

Έχω κολλήσει στα ??? που μπορείτε να δείτε στο παραπάνω php method.
biweekly σημαίνει δύο εβδομάδες μετά, την ανάλογη ημέρα, με βάση την date_added.
monthly σημαίνει ένα μήνα μετά, την ανάλογη ημέρα, με βάση την date_added.

Παραδείγματα του τι πρέπει να επιστρέφει:
Το task δημιουργήθηκε την Τρίτη 19 Ιουλίου (date_added). Η monday είναι η frequency_option.

Αν το frequency του task είναι daily, πρέπει να επιστρέφει κάθε μέρα true (ΟΚ!)

Αν το frequency του task είναι weekly, η method πρέπει να επιστρέψει true:

στις 25 Ιουλίου (monday)
την 1η Αυγούστου (monday)
στις 8 Αυγούστου (monday)
στις 15 Αυγούστου (monday)
στις 22 Αυγούστου (monday)
στις 29 Αυγούστου (monday)
κτλ --> (ΟΚ!)

Αν το frequency του task είναι biweekly, η method πρέπει να επιστρέψει true:
την 1η Αυγούστου (monday)
στις 15 Αυγούστου (monday)
στις 29 Αυγούστου (monday)
στις 12 Σεπτεμβρίου (monday)
κτλ -> Τι πρέπει να κάνω;

Αν το frequency του task είναι monthly, η method πρέπει να επιστρέψει true:
στις 22 Αυγούστου (monday)
στις 19 Σεπτεμβρίου (monday)
στις 24 Οκτωβρίου (monday)
κτλ -> Τι πρέπει να κάνω;

Καμιά ιδέα; :)

 

Επεξ/σία από philos
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)

όπως το λέει ο @WebDevGr στο κάθε δύο βδομάδες θα ελέγχεις αν το difftime σε μέρες μεταξύ today kai date_added είναι πολλαπλάσιο του 14 px  Diffdays % 14 ==0

Στο κάθε μήνα ελέγχεις εάν έχει αλλάξει ο μήνας και έχεις ίδια ημερομηνία. Προσοχή αν το task ξεκινάει 31 τον επόμενο μήνα πρέπει να τρέξει μια μέρα νωρίτερα 30 δηλαδή ή άν είναι φεβρουάριος 28 αν είναι δίσεκτο έτος 29 . Επίσης μπορεί να είσαι το ίδιο μήνα αλλά σε άλλο έτος οπότε ελέγχεις και αυτό. 

H άλλη λύση είναι βάζεις το crontab να σου κάνει τη δουλειά

Επεξ/σία από k33theod
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)

Ευχαριστώ πολύ για τη βοήθεια παιδιά @WebDevGr @k33theod, το εκτιμώ! :)

Λοιπόν κοιτάξτε. Αν κάνω αυτό:

		if ($this->frequency == 'biweekly')
		{
			$Diffdays = intval(round((strtotime(date("Y-m-d")) - strtotime(date("Y-m-d", $this->date_added) . ' + 14 days')) / (60 * 60 * 24)));
			if ($day == $this->frequency_option && ($Diffdays % 14 == 0))
			{
				return true;
			}
		}

... δεν επιστρέφει ποτέ το true γιατί πολύ δύσκολο να συμπίπτει το πολλαπλάσιο του 14 με το $day ==  $this->frequency_option.

Αν κάνω αυτό μόνο:

			if ($Diffdays % 14 == 0)
			{
				return true;
			}

... παρουσιάζεται το πρόβλημα ότι δεν επιστρέφει τις Δευτέρες (monday) που είναι το $this->frequency_option, αλλά η αντίστοιχη μόνο εντός 14ρων ημερών που το πιο πιθανό θα είναι να μην είναι monday.

Δείτε πάλι το παράδειγμα και θα καταλάβετε:

Το task δημιουργήθηκε την Τρίτη 19 Ιουλίου (date_added). Η monday είναι η frequency_option.

Αν το frequency του task είναι biweekly, η method πρέπει να επιστρέψει true:
την 1η Αυγούστου (monday)
στις 15 Αυγούστου (monday)
στις 29 Αυγούστου (monday)
στις 12 Σεπτεμβρίου (monday)

Όπως καταλαβαίνετε, το σκέτο if ($Diffdays % 14 == 0) μπορεί να μην επιστρέψει monday, άρα δεν μας κάνει. ;)

Επεξ/σία από philos
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Πρέπει να δεις λίγο τα time functions Πως δουλεύουν τι επιστρέφουν κλπ

 $origin = new DateTime('2022-07-23');
    
    $target = new DateTime('2022-10-13');
    $interval = $origin->diff($target);
    $interval_in_days = $interval->days;
    var_dump($interval_in_days % 14 ==0);
    
    $target2 = new DateTime('2022-10-15');
    $interval2 = $origin->diff($target2);
    $interval_in_days2 = $interval2->days;
    var_dump($interval_in_days2 % 14 ==0);

    echo $origin->format("D, d M y")."\n";
    
    echo $target->format("D, d M y")."\n";
    echo $target2->format("D, d M y")."\n";

Το παραπάνω δηλαδή επιστρέφει

bool(false)
bool(true)
Sat, 23 Jul 22
Thu, 13 Oct 22
Sat, 15 Oct 22

που είναι οκ

1 ώρα πριν, philos είπε

... παρουσιάζεται το πρόβλημα ότι δεν επιστρέφει τις Δευτέρες (monday) που είναι το $this->frequency_option, αλλά η αντίστοιχη μόνο εντός 14ρων ημερών που το πιο πιθανό θα είναι να μην είναι monday.

Αυτό που λες δεν ίσχυει 7*ν ημέρες μετά την δευτέρα θα είναι πάντα δευτέρα. Μιλώντας πάντα για το δικό μας ημερολογιακό σύστημα που η εβδομάδα έχει 7 ημέρες και είναι κυλιόμενες η μία μετά την άλλη

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

@k33theod ναι καταλαβαίνω τι λες.

Πράγματι μετά από 7 μέρες θα είναι monday, άρα το πρόβλημα εμφανίζεται στην πρώτη ημερομηνία, δηλαδή στο παράδειγμα να πάμε από την Τρίτη 19 Ιουλίου (date_added) στην 1η Αυγούστου (monday) και μετά να κάνουμε υπολογισμό κάθε 14 μέρες, έτσι όλες οι υπόλοιπες ημερομηνίες θα βγαίνουν σωστές.

Ουσιαστικά το πρόβλημα είναι να πέφτει monday, η πρώτη μετά τις 14 μέρες. Και ύστερα μια χαρά κάνουμε +14 μέρες.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)

Νομίζω την παράμετρο frequency_option αυτό με τις μέρες δηλαδή δεν το χρειάζεσαι καθόλου. Τα τιμε objects της php θα κάνουν τη δουλειά.

12 λεπτά πριν, philos είπε

Ουσιαστικά το πρόβλημα είναι να πέφτει monday, η πρώτη μετά τις 14 μέρες. Και ύστερα μια χαρά κάνουμε +14 μέρες.

Πάντα θα πέφτει Monday δεν υπάρχει τέτοιο θέμα ούτε πρόβλημα κάπου μπερδεύσαι. Όπως σου είπα αν σήμερα είναι μέρα α μετά από ν*7 ημέρες θα είναι πάλι α.

Εκτός αν εννοείς ότι ο χρήστης έχει date_added Δευτέρα αλλά θέλει να τρέχει κάθε Τετάρτη ασ πούμε. Τότε αντί του date_added θα πρέπει να ορίσεις ώς αρχή την ημερομηνία που θα τρέξει 1η φορά το script

Επεξ/σία από k33theod
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)
12 λεπτά πριν, k33theod είπε

Νομίζω την παράμετρο frequency_option αυτό με τις μέρες δηλαδή δεν το χρειάζεσαι καθόλου. Τα τιμε objects της php θα κάνουν τη δουλειά.

Πάντα θα πέφτει Monday δεν υπάρχει τέτοιο θέμα ούτε πρόβλημα κάπου μπερδεύσαι. Όπως σου είπα αν σήμερα είναι μέρα α μετά από ν*7 ημέρες θα είναι πάλι α.

Εκτός αν εννοείς ότι ο χρήστης έχει date_added Δευτέρα αλλά θέλει να τρέχει κάθε Τετάρτη ασ πούμε. Τότε αντί του date_added θα πρέπει να ορίσεις ώς αρχή την ημερομηνία που θα τρέξει 1η φορά το script

hmm είσαι σίγουρος; Κάπου μάλλον το χάνω.
Σκέψου ότι το frequency_option παίρνει τιμές, όλες τις ημέρες της εβδομάδας, άρα κάπου χρειάζεται. Το Τρίτη 19 Ιουλίου data_added με monday frequency_option είναι ένα παράδειγμα που τυχαίνει να είναι διπλανές οι ημέρες.
Τι θα γίνει αν έχουμε date_added Τρίτη 19 Ιουλίου και frequency_option την friday;

Θα πρέπει το biweekly να επιστρέφει true τις ακόλουθες ημερομηνίες:
5 Αυγούστου (friday) -> 17 μέρες μετά η πρώτη friday με συμπλήρωση 14ρων ημερών (biweekly)
19 Αυγούστου (friday) -> 14 μέρες μετά... ok.
2 Σεπτεμβρίου (friday) -> 14 μέρες μετά... ok.
16 Σεπτεμβρίου (friday) -> 14 μέρες μετά... ok.

and so on

Επεξ/σία από philos
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ναί αυτό σου είπα στην τελευταία παρ.

Δεν θα χρησιμοποιήσεις στους υπολογισμούς το date_added γιατί δεν παίζει στην ουσία κανένα ρόλο. Θα χρησιμοποιήσεις την ημερομηνία της πρώτης Παρασκευής μετά την Τρίτη. Ονόμασε το ίσως κάπως αλλιώς. Πως θα βρεις την ημερομηνία της 1ης Παρασκευής μετά την Τρίτη 19 Ιουλ  είναι πάλι πρόβλημα

$start_day = date_added->add(new DateInterval('P3D'));

Πώς βγαίνει το 3 πρέπει να το βρεις μόνος σου 😃

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)

Λοιπόν @k33theod, νομίζω το κατάφερα! :)

Το ακόλουθο δίνει ακριβώς τις ημερομηνίες που θέλω όταν τρέχει (το $base το έβαλα για λόγους debugging ώστε να βάζω test ημερομηνίες).

	protected function daysUntil($start, $end) 
	{
		$lookup = [
			'sunday' => 0,
			'monday' => 1,
			'tuesday' => 2,
			'wednesday' => 3,
			'thursday' => 4,
			'friday' => 5,
			'saturday' => 6
		];
		$days = $lookup[$end] - $lookup[$start] + ($lookup[$end] <= $lookup[$start] ? 7 : 0);
		
		return intval($days);
	}
	
	public function canAssignedToday($base)
	{
		if (!$base)
		{
			$base = time();
		}
		
		$day = strtolower(date('l', $base));
		// [...]
		if ($this->frequency == 'biweekly')
		{
			if ($day == $this->frequency_option)
			{
				$daysUntil = $this->daysUntil(strtolower(date('l', $this->date_added)), $day);
				
				$origin = new \DateTime();
				$origin = $origin->setTimestamp($base);
				
				$target = new \DateTime();
				$target = $target->setTimestamp($this->date_added);
				$target = $target->add(new \DateInterval('P' . intval($daysUntil) . 'D'));

				$interval = $origin->diff($target);
				$interval_in_days = $interval->days;

				if ($interval_in_days > 0 && $interval_in_days % 14 == 0)
				{
					return true;
				}				
			}
		}

		return false;
	}

 

argh πρέπει να έχει κι άλλα θέματα το παραπάνω, θα το δω το βράδυ που θα γυρίσω!

Επεξ/σία από philos
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Λοιπόν παιδιά @k33theod, @WebDevGr η class method του παραπάνω post μου λειτουργεί μια χαρά για biweekly!

Μπορείτε να μου δώσετε tips και για το if ($this->frequency == 'monthly')?

Προφανώς δεν μπορώ να κάνω % 30 == 0 γιατί ένας μήνας μπορεί να έχει 28, 29, 30 ή 31 ημέρες.

Επίσης διάβασα ότι μερικές φορές το date_added->add(new DateInterval('P1M')); μπορεί να μην είναι τόσο αξιόπιστο.

Αν το frequency του task είναι monthly, με date_added 19 Ιουλίου και frequency_option = 'monday', η method πρέπει να επιστρέψει true:
στις 22 Αυγούστου (monday)
στις 19 Σεπτεμβρίου (monday)
στις 24 Οκτωβρίου (monday)

etc

Δοκίμασα να κάνω
 

                $target->add(new \DateInterval('P1M'));
                $interval = $origin->diff($target);
                $interval_in_days = $interval->days;
            
                if ($interval_in_days % 28 == 0
                        || $interval_in_days % 29 == 0
                        || $interval_in_days % 30 == 0
                        || $interval_in_days % 31 == 0)
                {
                    return true;
                }

Αλλά κάτι χάνω.
Κάθε βοήθεια ευπρόσδεκτη!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δεν ξέρω γιατί εσύ ή ομάδα που δουλεύεις βάζετε τέτοιους περιορισμούς και κάνετε τη ζωή σας δύσκολη.

Όταν κάτι είναι κάθε μήνα διαλέγεις μια ημερομηνία πχ 10 του μήνα και κάνεις το task τότε αναξάρτητα τι μέρα είναι.

Εφόσον η μέρα είναι σημαντική  μπορείς να πεις θα το κάνω κάθε μήνα την πρώτη, δεύτερη, τρίτη , τέταρτη  Παρασκευή πχ  Όλες οι μέρες επαναλαμβάνονται μέσα σε ένα μήνα ακόμη και φεβρουάριο τουλάχιστον τεσσερις φορές 4*7 = 28.  Για να βρεις τώρα ασπούμε την τρίτη Τρίτη. Βρίσκει την μέρα την 1 του μηνός έστω Δευτέρα βρίσκεις τη διαφορά από την Τρίτη είναι 1 άρα 1η Τριτη 2 3η Τρίτη 2+14.

Κατά τη γνώμη μου όσο πιο περίπλοκο το κάνεις η πιθανότητα να γίνει μλακια αυξάνεται εκθετικά.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...