Foros del Web » Programando para Internet » PHP »

[SOLUCIONADO] Información entre dos fechas

Estas en el tema de Información entre dos fechas en el foro de PHP en Foros del Web. Buenas noches a todos :) Comento, estoy desarrollando una web, y hay un tema con el que no me aclaro, no consigo lo siguiente: Imaginad ...
  #1 (permalink)  
Antiguo 24/06/2017, 13:18
 
Fecha de Ingreso: abril-2010
Mensajes: 267
Antigüedad: 14 años
Puntos: 1
Información entre dos fechas

Buenas noches a todos :)

Comento, estoy desarrollando una web, y hay un tema con el que no me aclaro, no consigo lo siguiente: Imaginad que tenemos dos inputs para fechas con el siguiente formato: YYYY-mm-dd

Tengo que aplicar según tres tipos de temporada (baja, media y alta) un suplemento a un precio base, los suplementos son: un suplemento de la temporada, y suplemento según cantidad de días (max 6 días de suplemento), es decir:

Por ejemplo:

- suplemento_temporada_alta + supl_tem_alta_1dia o supl_tem_alta_2dia o supl_tem_alta_3dia o supl_tem_alta_4dia o supl_tem_alta_5dia o supl_tem_alta_6dia

Las temporadas están comprendidas entre las siguientes fechas:

Temporada BAJA: 6 de Enero y 15 de Marzo
Temporada MEDIA: 16 de Marzo y 30 de Junio
Temporada ALTA: 1 de Julio y 31 de Octubre
Temporada BAJA: 1 de Noviembre y 15 de Diciembre
Temporada MEDIA: 16 de Diciembre y 5 de Enero

He estado dándole muchas vueltas y esto es lo mucho que he conseguido:

Código:
<?php

	require 'config.php';
	
	require 'template.php';
	
	if(!empty($_GET['vehicle'])) {
		
		$query = mysqli_query($config['mysqli']['connect'], 'SELECT * FROM `vehicles` WHERE `id` = ' . $_GET['vehicle']);
		
		while($vehicle = mysqli_fetch_array($query)) {
			
			/*
			
				Nota: El formato de fecha de entrada es YYYY-mm-dd
			
			*/
			
			$price = $vehicle['base_price'];
			
			/* Comprueba si la fecha esta entre dos fechas */
			
			function check_in_season($date, $season_start, $season_end) {
				
				return (strtotime($date) >= strtotime($season_start) && strtotime($date) <= strtotime($season_end) ? true : false);
				
			}
			
			/* Devuelve el numero de dias entre dos fechas */
			
			function restar_fechas($start, $end) {
				
				$days = strtotime($start) - strtotime($end);
				
				return abs(intval($days/60/60/24));
				
			}
			
			/* */
			
			function comprobar_temporada($inicio, $fin, $date_entrega, $date_devolucion) {
				
				if(strtotime($date_entrega) >= strtotime($inicio) && strtotime($date_entrega) <= strtotime($fin)) {
				
					return (strtotime($date_devolucion) >= strtotime($inicio) && strtotime($date_devolucion) <= strtotime($fin) ? true : false);
					
				} else {
				
					return false;
				
				}
				
			}
			
			/* Comprueba en que temporada estamos */
			
			function season($date) {
				
				$year = date('Y', strtotime($date));
				
				if(check_in_season($year . '-01-06', $year . '-03-15', $date) || check_in_season($year . '-11-01', $year . '-12-15', $date)) {
					
					return 1;
					
				} else if(check_in_season($year . '-12-16', $year + 1 . '-01-05', $date) || check_in_season($year . '-03-16', $year . '-06-30', $date)) {
					
					return 2;
					
				} else if(check_in_season($year . '-07-01', $year . '-10-31', $date)) {
					
					return 3;
					
				} else {
					return false;
				}
				
			}
			
			/* Sistema de anadir suplementos */
			
			$between_seasons = false;
			
			if(5==3) {
				
				/* Aqui iria lo mismo si estamos en la misma estacion */
				
			} else {
				
				/* En caso de que estemos entre temporadas */
				
				$between_seasons = true;
				
				/* Bucle por cada temporada */
				
				for($i = 1; $i <= 3; $i++) {
					
					/* Bucle para comprobar la temporada para la fecha de ENTREGAR */
					
					if(season($_GET['date_re']) == $i) {
						
						/* Anadimos suplemento generico por temporada */
						
						$season_supplement = ($i == 3 ? 'high_season_supplement' : ($i == 2 ? 'half_season_supplement' : 'low_season_supplement'));
						
						/* hacemos bucle para comprobar los dias y segun el dia anadimos el suplemento especifico */
						
						for($x = 1; $x <= 6; $x++) {
							
							if(restar_fechas($_GET['date_re'], $_GET['date_de']) == $x) {
								
								$season_supplement_days = $season_supplement . '_' . $x . '_days';
								
							}
							
						}
						
						echo 're: ' . $season_supplement . ' + ' . $season_supplement_days;
						
					}
					
					/* Bucle para comprobar la temporada para la fecha de DEVOLVER */
					
					if(season($_GET['date_de']) == $i) {
						
						/* Anadimos suplemento generico por temporada */
						
						$season_supplement = ($i == 3 ? 'high_season_supplement' : ($i == 2 ? 'half_season_supplement' : 'low_season_supplement'));
						
						/* hacemos bucle para comprobar los dias y segun el dia anadimos el suplemento especifico */
						
						for($x = 1; $x <= 6; $x++) {
							
							if(restar_fechas($_GET['date_re'], $_GET['date_de']) == $x) {
								
								$season_supplement_days = $season_supplement . '_' . $x . '_days';
								
							}
							
						}
						
						echo 'de: ' . $season_supplement . ' + ' . $season_supplement_days;
						
					}
					
				}
				
				/* if($suplemento_temporada_fecha_1 <= $suplemento_temporada_fecha_2) {
					
					$price = (($price + $suplemento_temporada_fecha_2) * restar_fechas($_GET['date_re'], $_GET['date_de'])) + $suplementos_temporada_fecha_2;
					
				} else {
					
					$price = (($price + $suplemento_temporada_fecha_1) * restar_fechas($_GET['date_re'], $_GET['date_de'])) + $suplementos_temporada_fecha_1;
					
				} */
			
			}
			
			/* echo round($price, 2); */
		
		}
	
	}
Siento que esté un poco liado todo pero tengo un jaleo enorme, este sistema según he estado dandole vueltas, la idea me serviría si o la fecha de recogida del vehículo y la de devolución se encuentra en el mismo mes o una en este mes y la otra en el siguiente, por lo que si dejase un mes de por medio fallaría. Entiendo que por bucles sacando los meses que hay de por medio y los días de esos meses que se seleccionan podría seguir el código. Pero no lo he conseguido.

Os agradezco muchísimo la ayuda de antemano
  #2 (permalink)  
Antiguo 24/06/2017, 16:19
alvaro_trewhela
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Información entre dos fechas

Ve como andas con esto, eso sí no lo probé, pero está libre de errores de sintáxis y eso... lo hice un poco a la rápida, pero espero que se entienda la idea:

Código PHP:
Ver original
  1. <?php
  2.  
  3. //================ Config ================//
  4.  
  5. //---- Suplementos-----//
  6. $suplemento = array(
  7. array( //config temp. baja
  8. 1000, //suplemento
  9. 900, //dias: 1
  10. 800, //dias: 2
  11. 700, //dias: 3
  12. 600, //dias: 4
  13. 500, //dias: 5
  14. 400 //dias: 6
  15. ),
  16. array( //config temp. media
  17. 2000, //suplemento
  18. 900, //dias: 1
  19. 800, //dias: 2
  20. 700, //dias: 3
  21. 600, //dias: 4
  22. 500, //dias: 5
  23. 400 //dias: 6
  24. ),
  25. array( // config, temp. alta
  26. 3000, //suplemento
  27. 900, //dias: 1
  28. 800, //dias: 2
  29. 700, //dias: 3
  30. 600, //dias: 4
  31. 500, //dias: 5
  32. 400 //dias: 6
  33. )
  34. );
  35. //-----End suplementos-----//
  36.  
  37. $precio_base = 7000; //precio base
  38.  
  39. $fecha = $_POST["fecha"]; // ve como arreglas tu post de fecha
  40. $dias = $_POST["dias"]; // ve como arreglas tu post de dias
  41.  
  42. //================ End Config ================//
  43.  
  44. function entreFechas($inicio, $fin, $fecha){
  45.     if(strtotime($fecha) >= strtotime($inicio) && strtotime($fecha) <= strtotime($fin)){ return true; }
  46. return false;
  47. }
  48.  
  49. $dias = intval($dias);
  50. $year = intval(explode("-",$fecha)[0]);
  51. $temporada = 1;
  52.  
  53. if(entreFechas("$year-07-01","$year-10-31",$fecha)){
  54. $temporada = 2;
  55. }
  56. else if(entreFechas("$year-06-15","$year-03-15",$fecha) || entreFechas("$year-09-01","$year-12-15",$fecha)){
  57. $temporada = 0;
  58. }
  59.  
  60. $total = $precio_base+$suplemento[$temporada][0]+$suplemento[$temporada][$dias];
  61.  
  62. echo $total;
  63.  
  64. ?>

Saludos.
  #3 (permalink)  
Antiguo 24/06/2017, 16:27
 
Fecha de Ingreso: abril-2010
Mensajes: 267
Antigüedad: 14 años
Puntos: 1
Respuesta: Información entre dos fechas

Hola alvaro_trewhela ,

Mil gracias por el código, lo he probado, pero mientras no habían mensajes he estado a ver si se me ocurría algo y he conseguido pensar lo siguiente, te lo adjunto, pero tengo un problema, si restas con alguna web ambas fechas, te sale una diferencia de 20 días menos, supongo que el fallo está en el bucle pero no sé solucionarlo, a ver si supieras, porque creo que este es algo más simple y con este ya me podría valer:

Código:
<?php

	$seasons = array();
	$seasons['low']['days'] = 0;
	$seasons['half']['days'] = 0;
	$seasons['high']['days'] = 0;

	$recogida = '2017-06-10';
	
	$devolucion = '2018-07-20';
	
	$price = 500;
	
	/* Anade dias uno a uno entre las dos fechas a un array en una variable */
	
	$difference = date_diff(date_create($recogida), date_create($devolucion));
	
	for($now = 0; $now <= $difference->format('%a'); $now++) {
		
		$timestamp = strtotime($recogida . '+ ' . $now . ' day');
		
		/* Format: Ymd */
		
		$day = date('Ymd', $timestamp);
		
		if((date('Y0106', $timestamp) <= $day && $day <= date('Y0315', $timestamp)) or (date('Y1101', $timestamp) <= $day && $day <= date('Y1215', $timestamp))) {
			
			$seasons['low']['days']++;
			
		} else if ((date('Y0316', $timestamp) <= $day && $day <= date('Y0630', $timestamp)) or (date('Y1216', $timestamp) <= $day && $day <= date('Y0105', $timestamp))) {
			
			$seasons['half']['days']++;
			
		} else if (date('Y0701', $timestamp) <= $day && $day <= date('Y1031', $timestamp)) {
			
			$seasons['high']['days']++;
			
		}
		
	}
	
	/* Sumar y mostrar */
	
	echo '<b>' . $recogida . ' / ' . $devolucion . '</b><br>';
	echo '<b>Precio base:</b> ' . $price . '$<br>';
	
	if($seasons['low']['days']) {
		
		$price = $price + ($seasons['low']['days'] * 2);
		
		echo 'Con suplemento temporada <b>baja</b>: ' . $price . '$ (' . $seasons['low']['days'] . ' dias a 2$) (Suplemento: ' . $seasons['low']['days'] * 2 . '$)<br>';
		
	}
	
	if($seasons['half']['days']) {
		
		$price = $price + ($seasons['half']['days'] * 4);
		
		echo 'Con suplemento temporada <b>media</b>: ' . $price . '$ (' . $seasons['half']['days'] . ' dias a 4$) (Suplemento: ' . $seasons['half']['days'] * 4 . '$)<br>';
		
	}
	
	if($seasons['high']['days']) {
		
		$price = $price + ($seasons['high']['days'] * 6);
		
		echo 'Con suplemento temporada <b>alta</b>: ' . $price . '$ (' . $seasons['high']['days'] . ' dias a 6$) (Suplemento: ' . $seasons['high']['days'] * 6 . '$)<br>';
		
	}
	
	echo '<b>Total:</b> ' . $price . '$';
Gracias de verdad por tu tiempo un abrazo :)
  #4 (permalink)  
Antiguo 24/06/2017, 17:42
alvaro_trewhela
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Información entre dos fechas

Para lo tuyo lo más seguro es que

Código PHP:
Ver original
  1. $difference = date_diff(date_create($recogida), date_create($devolucion));

Te esté dando un número negativo aplica absoluto:

Código PHP:
Ver original
  1. $difference = abs($difference)

Me equivoqué en mi código, cambia:

Código PHP:
Ver original
  1. else if(entreFechas("$year-06-15","$year-03-15",$fecha) || entreFechas("$year-09-01","$year-12-15",$fecha)){

Por

Código PHP:
Ver original
  1. else if(entreFechas("$year-01-06","$year-03-15",$fecha) || entreFechas("$year-09-01","$year-12-15",$fecha)){

Y en el calculo también me equivoqué:

Código PHP:
Ver original
  1. $total = $precio_base+$suplemento[$temporada][0]+$suplemento[$temporada][$dias];

Por

Código PHP:
Ver original
  1. $total = $precio_base+$suplemento[$temporada][0]+$suplemento[$temporada][$dias]*$dias;

Te complicas mucho, no es necesario pedir dos fechas, simplemente pides al cliente la fecha de ingreso y númerio de días de estadía, punto. así te ahorras hacer bucles y validaciones.

Por otro lado, deja por defecto temporada media, y luego verificas temporada alta o baja, no es necesario hacer 3 verificaciones, digo lo de temporada media para no lidiar con ese cambio de año: Temporada MEDIA: 16 de Diciembre y 5 de Enero

Luego como explicas:

supl_tem_alta_1dia o supl_tem_alta_2dia o etc...

Entiendo pues que hay varianza pero no fórumla, por eso creé ese arreglo de suplementos.

Eso por ahora. Saludos.
  #5 (permalink)  
Antiguo 25/06/2017, 11:20
 
Fecha de Ingreso: abril-2010
Mensajes: 267
Antigüedad: 14 años
Puntos: 1
Respuesta: Información entre dos fechas

Hola alvaro_trewhela :)

Perfecto, ya lo he solucionado, mil gracias de verdad, voy a adaptarlo tal como me has comentado, considero que es lo mejor, así me evito bucles innecesarios.

Te doy el voto y marco como solucionado ^^

Etiquetas: fecha, mysql, select, sql
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 16:06.