Vuelva a enchufarlo esta noche o este fin de semana

20

Este es mi primer código de golf, así que avíseme si es demasiado amplio o si me falta información para un buen rompecabezas.

Desafío

En Ontario y posiblemente en otras áreas del mundo, la electricidad se factura utilizando el precio por tiempo de uso (TOU) , que varía el costo por kilovatio-hora según el uso de la energía.

Dada una fecha y hora, quiero saber si estoy en un período de tiempo pico (rojo), medio pico (amarillo) o fuera de pico (verde).

Entrada

Suponga que la entrada se proporciona en un formato de fecha y hora ISO 8601 sin zona horaria aceptable con la precisión mínima de horas: YYYY-MM-DDThh[:mm[:ss]](la T es literal).

Ejemplos

  • 2014-09-01T14
  • 2014-09-01T17: 30
  • 2014-09-01T17: 30: 02

Salida

La salida debe ser una cadena On, Mido Off.

Reglas

  • El código más corto gana
  • Para los propósitos de este desafío, ignore las vacaciones legales
  • Asume la información encontrada en esta publicación. Las reglas reales de fijación de precios por tiempo de uso pueden cambiar en el futuro por el Ministerio de Energía de Ontario.

Información

Días laborables de verano (del 1 de mayo al 31 de octubre)

Reloj de tiempo de uso para los días de semana de verano

  • Fuera de horas punta: 19h00 - 07h00
  • Pico medio: 07h00 - 11h00 y 17h00 - 19h00
  • En horas pico: 11h00 - 17h00

Días laborables de invierno (del 1 de noviembre al 30 de abril)

Reloj de tiempo de uso para los días de semana de invierno

  • Fuera de horas punta: 19h00 - 07h00
  • Pico medio: 11h00 - 17h00
  • En horas pico: 07h00 - 11h00 y 17h00 - 19h00

Fines de semana

Reloj de tiempo de uso los fines de semana

  • Fuera de horas punta: todo el día
rink.attendant.6
fuente
¿Estás seguro de que los días de semana de invierno no se intercambian a mitad de pico / pico?
John Dvorak
3
@ JanDvorak, en invierno la gente usa luces y calefacción por la mañana y por la tarde; en verano usan aire acondicionado al mediodía.
Peter Taylor
44
Este es un duplicado límite de codegolf.stackexchange.com/q/7008/194 ( analice una fecha y hora y haga un cálculo simple en función de si es un día hábil o no). Creo que la dependencia de la temporada es lo suficientemente diferente, pero otros pueden estar en desacuerdo.
Peter Taylor
@PeterTaylor las reglas parecen mucho más simples aquí que en la pregunta vinculada. Esto no tiene que manejar años bisiestos, por ejemplo.
John Dvorak
3
¿Debería ser el formato de fecha general YYYY-MM-DDThh[:mm[:ss]]ya que los segundos solo se pueden aplicar si se aplican minutos?
Cruncher

Respuestas:

3

Ruby - 147 144 143 141 137 135

x=->s{y,m,d,h=s.scan(/\d+/).map &:to_i
g=Time.new(y,m,d).wday%6<1?0:[0..11,4..9].count{|r|r===h-7}
%W{Off Mid On}[m<5||m>10?(3-g)%3:g]}

Esto representa una función que toma una cadena como parámetro y devuelve una cadena.

Aquí hay una demostración en línea con algunos casos de prueba: http://ideone.com/wyIydw

Cristian Lupascu
fuente
8

Python 2 - 164

from datetime import*
d,t=input().split('T')
y,m,d=map(int,d.split('-'))
t=int(t[:2])
print'OMOfinfd'[(1+((10<t<17)==(4<m<11)))*(date(y,m,d).weekday()<5<6<t<19)::3]

Si es necesario, a continuación hay una explicación de la lógica en la línea final:

La línea final imprime una porción 'OMOfinfd'dependiendo de la evaluación de sus condicionales.

  • Primero, evalúe la operación 1+((10<t<17)==(4<m<11)).

    Si el XNOR entre las condiciones 10<t<17y 4<m<11es False, esto se evaluará a 1+False => 1+0 => 1. De lo contrario, la operación evaluará a 1+True => 1+1 => 2.

  • Finalmente, multiplique ese resultado de la operación anterior por si el día es un día de la semana y si la hora es entre las 6 am y las 7 pm.

    Si es así False, o bien el día es un fin de semana o la hora es entre las 7 pm-6am, y el resultado será (1|2)*0 => 0. De lo contrario, el resultado será (1|2)*1 => 1|2.

Un resultado de 0imprimirá Off, 1imprimirá Mide 2imprimirá On.

BeetDemGuise
fuente
¿La versión de golf no es realmente más larga porque usa punto y coma? ¿O se cuentan las nuevas líneas?
Beta Decay
Las nuevas líneas suelen contarse. En Notepad ++ (donde normalmente obtengo mis cuentas) la versión sin golf es 4bytes más larga en 168.
BeetDemGuise
3
@BeetDemGuise Editar → Conversión EOL → Formato UNIX / OSX.
Cisma
5

C # - 240220 caracteres

string x(string s){var d=DateTime.Parse((s+":00:00").Substring(0,19));int h=d.Hour,i=(int)d.DayOfWeek,x=d.Month;string o="off",m="mid",f="on";return i==6|i==0?o:x>=5&x<11?h>18|h<7?o:h>10&h<17?f:m:h>18|h<7?o:h>10&h<17?m:f;}

Nada especial. Codificación directa.

Gracias a w0lf :)

Stephan Schinkel
fuente
1
Creo que puedes acortar s.Length==13?s+":00:00":s.Length==16?s+":00":sa(s+":00:00").Substring(0,19)
Cristian Lupascu
5

Rubí - 135

Abusa del módulo Tiempo. Entrada por argumento de línea de comando.

d=Time.new(*$*[0].scan(/\d+/)[0..3])
o,m,f=%w{On Mid Off}
o,m=m,o if (d.mon-5)%10<6
p d.wday%6<1||(12>h=(d.hour+5)%24)?f:15<h&&h<22?m:o

Editar: Gracias w0lf por el tiempo que ayudó a acortar y resolver un error.

Vectorizado
fuente
Tu programa es incorrecto. Para la entrada 2014-09-01T17:30sale correctamente "Mid", pero para 2014-09-01T17ella sale "Off".
Cristian Lupascu
3

Groovy - 621 534 524 491 caracteres

Un poco más de golf para hacer, pero bastante simple al aprovechar Joda-Time

@Grab(group='joda-time',module='joda-time',version='2.3')
f={p,a->org.joda.time.format.DateTimeFormat.forPattern(p).parseDateTime a}
g={p,a->def x=null;try{x=f p,a}catch(Exception e){}}
a=args[0]
d=["",":mm",":mm:ss"].collect{g "yyyy-MM-dd'T'HH$it",a}.find{it}
r="Off"
m="Mid"
j={d,a,b->d.hourOfDay>a&&d.hourOfDay<b}
k={j(it,6,11)||(j(it,16,19))}
if(d.dayOfWeek<6){x=d.monthOfYear;if(x>4&&x<12){if(j(d,10,17))r="On";if(k(d))r=m}else if(x<5||x>10){if(j(d,10,17))r=m;if(k(d))r="On"}}
println r

ejecuciones de muestra:

bash-3.2$ ./run.peak.sh 
groovy Peak.groovy 2014-08-26T19
Off
groovy Peak.groovy 2014-08-26T07:00
Mid
groovy Peak.groovy 2014-08-26T18:00:00
Mid
groovy Peak.groovy 2014-08-26T12:30:30
On
groovy Peak.groovy 2014-11-01T00
Off
groovy Peak.groovy 2014-02-05T11:11:11
Mid
groovy Peak.groovy 2014-01-05T08:08
Off
groovy Peak.groovy 2014-12-18T18:59:59
On
groovy Peak.groovy 2014-08-31T14
Off

Sin golf:

@Grab(group='joda-time',module='joda-time',version='2.3')

f = { p,a -> org.joda.time.format.DateTimeFormat.forPattern(p).parseDateTime a}
g = { p,a -> def x=null; try{x=f p,a} catch(Exception e) {} }
a=args[0]

d = ["",":mm",":mm:ss"].collect{g "yyyy-MM-dd'T'HH$it",a}.find{it}
r = "Off"
m = "Mid"

j = {d,a,b -> d.hourOfDay > a && d.hourOfDay < b}
k = { j(it,6,11) || (j(it,16,19)) }

if (d.dayOfWeek<6) {
    x = d.monthOfYear;
    if ( x>4 && x<12 ) {
        if (j(d,10,17)) r="On";
        if (k(d)) r=m
    } else if (x<5||x>10) {
        if (j(d,10,17)) r=m;
        if (k(d)) r="On"
    }
}
println r
Michael Easter
fuente
2
Desde Java 8, también existe java.time.*, que es muy similar a Joda Time pero es parte del JRE. Quizás esto podría acortar un poco el código.
ntoskrnl
re: Java 8. excelente punto
Michael Easter
En su penúltimo ejemplo '2014-01-05T08:08', el 5 de enero de 2014 es un domingo. Por lo tanto, debería ser'Off'
BeetDemGuise
re: 5 de enero de 2014. Muy bien. El código actual es correcto, pero la ejecución de salida es incorrecta. Arreglará.
Michael Easter
Intentado java.time.*. falló miserablemente. El analizador es demasiado estricto. Úselo DateParserdesde nashorn (también parte del JRE8) que es indulgente y con un poco de pirateo abusivo, incluso lo suficientemente indulgente como para saltear minutos y segundos.
Mark Jeronimus
2

R, 243204 caracteres

b=strptime(scan(,""),"%Y-%m-%dT%H");i=function(x)as.integer(format(b,x));h=i("%H");d=i("%m%d");w=d>1100|d<430;f=ifelse;cat(c("Off","Mid","On")[f(i("%u")%in%5:6|h<7|h>19,1,f(h>11&h<17,f(w,2,3),f(w,3,2)))])

Sangrado y comentado:

b=strptime(scan(,""),"%Y-%m-%dT%H") #Takes stdin and converts into POSIXct
i=function(x)as.integer(format(b,x)) #Format the POSIXct and convert it to integer
h=i("%H")      #Format to hours
d=i("%m%d")    #Format to Month/Day
w=d>1100|d<430 #True if winter time, false if summer
f=ifelse
cat(c("Off","Mid","On")[f(i("%u")%in%5:6|h<7|h>19, #If weekend or night
                          1,                       #Case 1
                          f(h>11&h<17,            #Else if mid-day
                             f(w,3,2),             #Case 2 in winter, case 3 in summer
                             f(w,2,3)))])          #else vice versa

Ejemplos:

> b=strptime(scan(,""),"%Y-%m-%dT%H");i=function(x)as.integer(format(b,x));h=i("%H");d=i("%m%d");w=d>1100|d<430;f=ifelse;cat(c("Off","Mid","On")[f(i("%u")%in%5:6|h<7|h>19,1,f(h>11&h<17,f(w,3,2),f(w,2,3)))])
1: 2014-08-26T15
2: 
Read 1 item
On
> b=strptime(scan(,""),"%Y-%m-%dT%H");i=function(x)as.integer(format(b,x));h=i("%H");d=i("%m%d");w=d>1100|d<430;f=ifelse;cat(c("Off","Mid","On")[f(i("%u")%in%5:6|h<7|h>19,1,f(h>11&h<17,f(w,3,2),f(w,2,3)))])
1: 2014-12-10T15
2: 
Read 1 item
Mid
> b=strptime(scan(,""),"%Y-%m-%dT%H");i=function(x)as.integer(format(b,x));h=i("%H");d=i("%m%d");w=d>1100|d<430;f=ifelse;cat(c("Off","Mid","On")[f(i("%u")%in%5:6|h<7|h>19,1,f(h>11&h<17,f(w,3,2),f(w,2,3)))])
1: 2014-08-26T23
2: 
Read 1 item
Off
plannapus
fuente
1

Bash, 286

esta es una respuesta bash simple usando el programa de fecha

d(){ date -d $1 +%$2; };D=$(echo $1|sed 's/\(T..\)$/\1:00/');H=$(d $D H);M=$(d $D m);if [ $(d $D u) -gt 5 ]||[ $H -lt 7 ]||[ $H -gt 18 ];then echo Off;exit;fi;if [ $M -gt 4 ]&&[ $M -lt 11 ];then I=On;O=Mid;else I=Mid;O=On;fi;if [ $H -gt 10 ]&&[ $H -lt 17 ];then echo $I;else echo $O;fi
Optokopper
fuente
1

¡Aquí va otro!

JavaScript, 175 171

function f(x){d=new Date(x.slice(0,10));t=x.slice(11,13),m=(x.slice(5,7)+1)%12;return(t<8||t>18||!(d.getUTCDay()%6)?'off':((t<11||t>17)?(m<5?'on':'mid'):(m<5?'mid':'on'))}

No minificado:

function f(x) {
  d = new Date(x.slice(0, 10));
  t = x.slice(11, 13), m = (x.slice(5, 7) + 1) % 12;
  return (t < 8 || t > 18 || !(d.getUTCDay() % 6) ? 'off' : ((t < 11 || t > 17) ? (m < 5 ? 'on' : 'mid') : (m < 5 ? 'mid' : 'on'))
}

Solo funciona en intérpretes donde se puede pasar una cadena de fecha ISO8601 al Dateconstructor.

CoffeeScript, 192 189

Sorprendentemente, es más largo en CoffeeScript porque no hay un operador ternario en ese lenguaje (que como puede ver en mi JavaScript, confié mucho).

f=(x)->d=new Date(x.slice(0,10));t=x.slice(11,13);m=(x.slice(5,7)+1)%12;return'off'if(t<8||t>18||!(d.getUTCDay()%6));if(t<11||t>17)then(if m<5then'on'else'mid')else(if m<5then'mid'else'on')
rink.attendant.6
fuente
0

ES6 - 146

Esto está en forma de función, utiliza un par de trucos desagradables.

let y,m,d,h,c=s=>[y,m,d,h]=s.split(/[T:-]/g).map(i=>+i),new Date(y,m,d).getDay()in{0:1,6:1}||h<20||8>h?'Off':['Mid','On'][(10>h&&h>16)^(m>5||m<8)]

Explicado:

// These variables are declared outside of the function scope to save
// characters.
let y, // year
    m, // month
    d, // day
    h, // hour
    c = s => // c for check, called as c(isoString)
      [y, m, d, h] = // Assign to fields
        s.split(/[T:-]/g) // Split at delimiters
         .map(i => +i), // Convert all to numbers
                        // Comma used to keep it as a single statement.
      new Date(y, m, d).getDay() // Create Date to get day of week
        in {0:1, 6:1} // Check if it is good (0 = Sunday, 6 = Saturday). It
                      // is shorter to use an object literal than to
                      // do individual checks.
      ||
      h < 20 || 8 > h ? // h is between 7 and 19 (7pm)
       'Off' : // Return 'Off'
       ['Mid','On'][ // Two other outputs
        (10 > h && h > 16) ^ // Check if it is 11-16 (5pm)
        (m > 5 || m < 8)] // Invert that if the month is in summer/fall. Note
                          // that this returns a number, either 1 or 0. This
                          // is an ugly hack using the bitwise xor operator.
Isiah Meadows
fuente
0

Python 3 - 352 caracteres

import datetime as dt
t=input()
i=int
p=print
a='on'
b='mid'
c='off'
m=i(t[5:7])
h=i(t[11:13])
d=dt.date(i(t[0:4]),m,i(t[8:10])).weekday()
if 5==d or 6==d:p(c)
elif h>=19 and h<7:p(c)
elif m<=10 and m>=4:
 if h>=7 and h<11:p(b)
 if h>=11 and h<17:p(a)
 if h>=17 and h<19:p(b)
else:
 if h>=7 and h<11:p(a)
 if h>=11 and h<17:p(b)
 if h>=17 and h<19:p(a)
Decaimiento Beta
fuente
1
Debería cambiar s=['high','mid','off']a s=['on','mid','off']: esto no solo ahorra 2 caracteres, sino que la especificación dice que salga "on".
Sellyme
0

Java: 426309/301 ? (ver comentarios)

String z(String a){
    DateParser b=new DateParser(a);
    boolean c=b.parseEcmaDate();
    Integer[]d=b.getDateFields();
    GregorianCalendar e=new GregorianCalendar(d[0],d[1]-(c?0:1),d[2]);
    e.setTimeZone(new SimpleTimeZone(0,""));
    return(124>>e.get(7)&1)>0&d[3]>6&d[3]<19?
           d[3]>10&d[3]<17^(1008>>e.get(2)&1)>0?"Mid":"On":"Off";
}

Salida de ejemplo:

2014-03-02T00   Off
2014-03-02T06   Off
2014-03-02T07   Off
2014-03-02T10   Off
2014-03-02T11   Off
2014-03-02T16   Off
2014-03-02T17   Off
2014-03-02T18   Off
2014-03-02T19   Off
2014-03-02T23   Off
2014-04-02T00   Off
2014-04-02T06   Off
2014-04-02T07   On
2014-04-02T10   On
2014-04-02T11   Mid
2014-04-02T16   Mid
2014-04-02T17   On
2014-04-02T18   On
2014-04-02T19   Off
2014-04-02T23   Off
2014-05-02T00   Off
2014-05-02T06   Off
2014-05-02T07   Mid
2014-05-02T10   Mid
2014-05-02T11   On
2014-05-02T16   On
2014-05-02T17   Mid
2014-05-02T18   Mid
2014-05-02T19   Off
2014-05-02T23   Off

Usé el mismo truco EXOR que el envío de Python. También usé a +como una función OR, para cuando es weekend OR night.

Mi otro gran truco: máscaras de bits.

Por ejemplo, para ver si un número está entre 2 y 6 (de lunes a viernes), primero cree un patrón de bits donde los valores interesantes sean 1:

  6   2 
0b1111100 = 124

Luego, use bit shift para obtener el bit interesante para el LSB y extraerlo:

(124 >> day_of_week) & 1

Del mismo modo, hice patrones de bits durante meses y horas:

  9    4
0b1111110000 = 1008

      76          76
0b111110000000000001111111 = 16253055
0b000000011111100000000000 = 129024

Desafortunadamente, resulta que x>y&x<zes más corto en la mayoría de los casos, por lo que no lo usé en algunos lugares.

Y finalmente, un poco de piratería (altamente dependiente de la implementación) con jdk.nashorn.internal.parser.DateParser: Cuando parseEcmaDate()no analiza completamente una fecha (como cuando lee la hora y toca el final de la cadena), devuelve falso.

  • Cuando termina correctamente, la fecha se almacena en un Integer[](auto-unboxing ftw), con el mes fijado como base-0 (como otras clases de Java).
  • Cuando devuelve falso, abortó a mitad de camino y no hizo esta reparación. Sin embargo, todavía coloca lo que analizó en la matriz, que está fácilmente disponible. De ahí el -(c?0:1).
Mark Jeronimus
fuente
Creo que usar .parse()también podría funcionar (eliminar 8 caracteres), pero no lo he probado a fondo con diferentes entradas. parseinternamente llama parseEcmaDatey si falla, llama parseLegacyDate. Este último puede arruinar la matriz, pero esto no sucedió con algunos casos que probé.
Mark Jeronimus
-1

Nada me impide entrar por mi cuenta, y hay otras más cortas aquí de todos modos, así que ...

PHP 5.4+, 194

<?function f($x){$t=substr($x,11,2);$m=(substr($x,5,2)+1)%12;if($t<8||$t>18||(new DateTime(substr($x,0,10)))->format('N')>5)return'off';return($t<11||$t>17)?($m<5?'on':'mid'):($m<5?'mid':'on');}

Sin minificar y comentado:

<?
function f($x) {
  $t = substr($x,11,2); // hour
  $m = (substr($x,5,2) + 1) % 12; // month shifted up by 1

  if ($t < 8 || $t > 18 || (new DateTime(substr($x,0,10)))->format('N') > 5)
    return 'off'; // evenings and weekends

  return ($t < 11 || $t > 17)
    ? ($m < 5 ? 'on' : 'mid') // morning and mid-afternoon
    : ($m < 5 ? 'mid' : 'on'); // afternoon
}

También tenga en cuenta que la date.timezonedirectiva en php.ini debe establecerse, de lo contrario se lanzará una excepción.

rink.attendant.6
fuente