Conecte-o novamente hoje à noite ou neste fim de semana

20

Este é o meu primeiro código de golfe, então, deixe-me saber se é muito amplo ou se estou perdendo alguma informação para um bom quebra-cabeça!

Desafio

Em Ontário e possivelmente em outras áreas do mundo, a eletricidade é cobrada com base no preço do tempo de uso (TOU) , que varia o custo por quilowatt-hora de acordo com o uso da energia.

Dada a data e a hora, quero saber se estou no período de pico (vermelho), pico médio (amarelo) ou fora do pico (verde).

Entrada

Suponha que a entrada seja fornecida em um formato de data e hora ISO 8601 aceitável, sem fuso horário, com a precisão mínima de horas:YYYY-MM-DDThh[:mm[:ss]] (o T é literal).

Exemplos

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

Saída

A saída deve ser uma string On, MidouOff .

Regras

  • O código mais curto vence
  • Para os fins deste desafio, ignore os feriados legais
  • Suponha as informações encontradas nesta postagem. As regras reais de preços por tempo de uso podem mudar no futuro pelo Ministério da Energia de Ontário.

Em formação

Dias de semana de verão (1º de maio a 31 de outubro)

Relógio de hora de uso para dias de semana de verão

  • Fora do pico: 19h00 - 07h00
  • Pico médio: 07h00 - 11h00 e 17h00 - 19h00
  • No pico: 11h00 - 17h00

Dias úteis de inverno (1 de novembro a 30 de abril)

Relógio de ponto de uso para dias de semana de inverno

  • Fora do pico: 19h00 - 07h00
  • Pico médio: 11h00 - 17h00
  • No horário de pico: 07h00 - 11h00 e 17h00 - 19h00

Finais de semana

Relógio de ponto de uso nos finais de semana

  • Fora do pico: o dia todo
rink.attendant.6
fonte
Tem certeza de que os dias úteis de inverno não têm trocas no pico / no pico?
John Dvorak
3
@JanDvorak, no inverno, as pessoas usam luzes e aquecimento de manhã e à noite; no verão, eles usam ar-condicionado ao meio-dia.
Peter Taylor
4
Isso é uma duplicata limítrofe de codegolf.stackexchange.com/q/7008/194 (analise uma data e hora e faça um cálculo simples com base no dia útil ou não). Eu acho que a dependência da temporada é apenas diferente o suficiente, mas outros podem discordar.
Peter Taylor
@ PeterTaylor, as regras parecem muito mais simples aqui do que na questão vinculada. Isso não precisa lidar com anos bissextos, por exemplo.
John Dvorak
3
O formato geral da data deve ser YYYY-MM-DDThh[:mm[:ss]]porque os segundos só podem ser aplicados se os minutos forem aplicados?
Cruncher

Respostas:

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]}

Isso representa uma função que pega uma string como parâmetro e retorna uma string.

Aqui está uma demonstração on-line com alguns casos de teste: http://ideone.com/wyIydw

Cristian Lupascu
fonte
8

Python 2-166

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]

Se necessário, abaixo está uma explicação da lógica na linha final:

A linha final imprime uma fatia 'OMOfinfd'dependendo da avaliação de suas condicionais.

  • Primeiro, avalie a operação 1+((10<t<17)==(4<m<11)).

    Se o XNOR entre as condições 10<t<17e 4<m<11é False, este irá avaliar a 1+False => 1+0 => 1. Caso contrário, a operação será avaliada como 1+True => 1+1 => 2.

  • Por fim, multiplique o resultado da operação acima pelo dia da semana e o horário entre 6h e 19h.

    Se for esse o caso False, o dia é um fim de semana ou o horário é entre 19h e 6h, e o resultado será (1|2)*0 => 0. Caso contrário, o resultado será (1|2)*1 => 1|2.

Um resultado 0será impresso Off, 1impresso Mide 2impresso On.

BeetDemGuise
fonte
A versão golfed não é realmente mais longa porque você usa ponto e vírgula? Ou as novas linhas são contadas?
Deterioração beta
As novas linhas são normalmente contadas. No Notepad ++ (onde normalmente recebo minhas contagens), a versão não-gasta é 4 bytes a mais, com 168.
BeetDemGuise
3
@BeetDemGuise Editar → Conversão de EOL → Formato UNIX / OSX.
Schism
5

C # - 240 220 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. Codificação direta.

Graças a w0lf :)

Stephan Schinkel
fonte
1
Eu acho que você pode encurtar s.Length==13?s+":00:00":s.Length==16?s+":00":spara(s+":00:00").Substring(0,19)
Cristian Lupascu
5

Ruby - 135

Abusa do módulo Time. Entrada por argumento de linha 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

Edit: Obrigado w0lf pelo tempo que ajudou a diminuir e resolver um bug.

Vetorizado
fonte
Seu programa está incorreto. Para a entrada, 2014-09-01T17:30ele sai corretamente "Mid", mas para 2014-09-01T17ele "Off".
Cristian Lupascu
3

Groovy - 621 534 524 491 caracteres

Algum jogo a mais, mas bastante simples ao aproveitar o 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

execuções de amostra:

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

Ungolfed:

@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
fonte
2
Desde o Java 8, há também java.time.*, que é muito semelhante ao Joda Time, mas faz parte do JRE. Talvez isso possa reduzir um pouco o código.
Ntskrnl
re: Java 8. ponto excelente
Michael Easter
No seu penúltimo exemplo '2014-01-05T08:08', 5 de janeiro de 2014 é um domingo. Assim, deveria ser'Off'
BeetDemGuise
re: 5 de janeiro de 2014. Muito bem. O código atual está correto, mas a execução da saída está errada. Fixará.
Michael Easter
Tentei java.time.*. falhou miseravelmente. O analisador é muito rígido. Use DateParserdo nashorn (também parte do JRE8) que é branda e com um pouco de hackers abusivos, branda o suficiente para pular minutos e segundos.
Mark Jeronimus
2

R, 243 204 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)))])

Recuado e 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

Exemplos:

> 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
fonte
1

Bash, 286

esta é uma resposta simples do bash usando o programa date

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
fonte
1

Aqui vai outro!

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'))}

Desminificado:

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'))
}

Funciona apenas em intérpretes em que uma sequência de datas ISO8601 pode ser passada para o Date construtor.

CoffeeScript, 192 189

Surpreendentemente, é mais longo no CoffeeScript porque não há operador ternário nessa linguagem (na qual você pode ver no meu JavaScript, eu confiei bastante).

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
fonte
0

ES6 - 146

Isso está em forma de função, usa alguns hacks desagradáveis.

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
fonte
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)
Beta Decay
fonte
1
Você deve mudar s=['high','mid','off']para s=['on','mid','off']- não apenas isso salva 2 caracteres, mas a especificação diz para a saída "on".
Sellyme
0

Java - 426 309/301? (Ver comentários)

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";
}

Exemplo de saída:

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

Usei o mesmo truque do EXOR que o envio do Python. Eu também usei a +como uma função OR, para quando éweekend OR night .

Meu outro grande truque: máscaras de bits.

Por exemplo, para ver se um número está entre 2 e 6 (segunda a sexta-feira), primeiro crie um padrão de bits em que os valores interessantes sejam 1:

  6   2 
0b1111100 = 124

Em seguida, use bit shift para obter o bit interessante no LSB e extraí-lo:

(124 >> day_of_week) & 1

Da mesma forma, fiz padrões de bits por meses e horas:

  9    4
0b1111110000 = 1008

      76          76
0b111110000000000001111111 = 16253055
0b000000011111100000000000 = 129024

Infelizmente, acontece simplesmente x>y&x<z na maioria dos casos, é mais curto, então não o usei em alguns lugares.

E, finalmente, um pouco de hackery (altamente dependente da implementação) com jdk.nashorn.internal.parser.DateParser: Quando parseEcmaDate()não analisa completamente uma data (como quando lê a hora e atinge o final da string), ela retorna false.

  • Quando termina corretamente, a data é armazenada em um Integer[] (ftw de descompactação automática), com o mês fixado para ser a base 0 (como outras classes Java).
  • Quando retorna false, é anulado até a metade e não faz essa correção. No entanto, ainda coloca o que foi analisado na matriz, que está prontamente disponível. Daí o -(c?0:1).
Mark Jeronimus
fonte
Eu acho que o uso .parse()também pode funcionar (reduzindo 8 caracteres), mas não testei completamente com entradas diferentes. parsechama internamente parseEcmaDatee, se falhar, chama parseLegacyDate. O último pode estragar a matriz, mas isso não aconteceu com alguns casos que testei.
Mark Jeronimus
-1

Nada me impede de entrar na minha própria, e há outras mais curtas aqui de qualquer maneira, então ...

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');}

Não minificado e 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
}

Observe também que a date.timezonediretiva no php.ini deve ser definida, caso contrário, uma exceção será lançada.

rink.attendant.6
fonte