Skip to content

Instantly share code, notes, and snippets.

@jhthorsen
Last active February 19, 2016 06:38
Show Gist options
  • Save jhthorsen/54ae539a6d6d9cb520f3 to your computer and use it in GitHub Desktop.
Save jhthorsen/54ae539a6d6d9cb520f3 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
use Mojolicious::Lite;
use List::Util 'reduce';
use Time::Piece;
use Time::Seconds;
sub off {
return (
'01-01' => 'Nyttårsdag',
'04-02' => 'Skjærtorsdag',
'04-03' => 'Langfredag',
'04-05' => '1. påskedag',
'04-06' => '2. påskedag',
'05-01' => 'Arbeidernes dag',
'05-14' => 'Kristi Himmelfartsdag',
'05-17' => 'Grunnlovsdag',
'05-24' => '1. pinsedag',
'05-25' => '2. pinsedag',
'12-25' => '1. juledag',
'12-26' => '2. juledag',
);
}
sub christmas {
my ($t, $off) = @_;
my $ft = $off->{_christmas_ft} ||= do {
my ($start) = grep { $off->{$_} and $off->{$_} eq '1. juledag' } keys %$off;
$start = Time::Piece->strptime("$off->{year}-$start", '%Y-%m-%d') - ONE_DAY;
[$start->epoch, ($start + 7 * ONE_DAY)->epoch];
};
return $t->epoch >= $ft->[0] && $t->epoch <= $ft->[1];
}
sub easter {
my ($t, $off) = @_;
my $ft = $off->{_easter_ft} ||= do {
my ($end) = grep { $off->{$_} and $off->{$_} eq '2. påskedag' } keys %$off;
$end = Time::Piece->strptime("$off->{year}-$end", '%Y-%m-%d');
[($end - 7 * ONE_DAY)->epoch, $end->epoch];
};
return $t->epoch >= $ft->[0] && $t->epoch <= $ft->[1];
}
get '/' => sub {
my $c = shift;
my $end = $c->param('to') || localtime->ymd('-');
my $year = $end =~ /(\d\d\d\d)/ ? $1 : localtime->year;
my $t = Time::Piece->strptime("${year}-01-01T00:00:00", '%Y-%m-%dT%H:%M:%S');
my %off = off();
my $days = 0;
$c->stash(today => localtime->ymd('-'));
map { $c->param($_ => 1) } qw( christmas easter weekends ) unless defined $c->param('vacation_days');
$end = $end =~ /\d/ ? Time::Piece->strptime("${end}T23:59:59", '%Y-%m-%dT%H:%M:%S') : Time::Piece->new;
$off{holiday} = 0;
$off{year} = $year;
$off{vacation_days} = $c->param('vacation_days');
$off{christmas} = $c->param('christmas') ? 0 : undef;
$off{easter} = $c->param('easter') ? 0 : undef;
$off{weekends} = $c->param('weekends') ? 0 : undef;
while (1) {
last if $t >= $end;
if ($off{$t->strftime('%m-%d')}) {
$off{holiday}++;
}
elsif (defined $off{weekends} and $t->day =~ /^(?:Sat|Sun)/) {
$off{weekends}++;
}
elsif (defined $off{easter} and easter($t, \%off)) {
$off{easter}++;
}
elsif (defined $off{christmas} and christmas($t, \%off)) {
$off{christmas}++;
}
}
continue {
$days++;
$t += ONE_DAY;
}
$off{total} = reduce { $a + $b } map { $off{$_} || 0 } qw( weekends easter christmas holiday vacation_days );
$c->render(end => $end, days => $days, off => \%off, year => $year);
}, 'index';
app->start;
__DATA__
@@ index.html.ep
<html>
<head>
<title>Arbeidsdager <%= $year%></title>
%= stylesheet begin
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url(https://fonts.gstatic.com/s/lato/v11/8qcEw_nrk_5HEcCpYdJu8BTbgVql8nDJpwnrE27mub0.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url(https://fonts.gstatic.com/s/lato/v11/MDadn8DQ_3oT6kvnUq_2r_esZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
body, input, td {
font-size: 16px;
font-family: Lato, sans-serif;
margin: 0;
padding: 0;
}
h1 {
font-size: 2.5em;
width: 90%;
margin: 1em auto;
}
table {
border-collapse: collapse;
width: 90%;
margin: 0 auto;
}
table th {
padding: 0.8em 0.8em;
font-size: 1.2em;
font-weight: bold;
text-align: left;
border-bottom: 2px solid #3ae;
}
table td { padding: 0.5em 1em; }
tfoot td {
padding: 1em 1em;
border-top: 2px solid #ccc;
border-bottom: 6px double #f55;
}
.text-field {
background: #ffffff;
border: 1px dashed #aaa;
padding: 5px 7px;
margin: -5px 0;
}
.text-field:focus {
outline: 1px dashed #f77;
outline-offset: 0;
border-color: #fff;
}
.btn {
background-color: #3ae;
font-family: Lato, Arial;
font-weight: bold;
color: #ffffff;
border: 1px solid #057fd0;
padding: 8px 24px;
outline: 0;
display: inline-block;
cursor: pointer;
text-decoration: none;
}
.container {
margin: 3em;
}
@media (max-width: 800px) {
table, h1 { width: 100%; margin: 1em 0; }
.container { margin: 1em 0.5em; };
}
% end
</head>
<body>
<div class="container">
<h1>Arbeidsdager i <%= $year %></h1>
%= form_for 'index', begin
<table>
<thead>
<tr>
<th>&nbsp;</th>
<th>Beskrivelse</th>
<th>Dager</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
<tr>
<td>&#160;</td>
<td><%= $year %>-01-01 til <%= text_field to => $today, size => 12, autocomplete => 'off', placeholder => $today, class => 'text-field' %></td>
<td><%= $days %></td>
<td>&#160;</td>
</tr>
<tr>
<td>-</td>
<td>Lør- og søndag</td>
<td><%= $off->{weekends} || 0 %></td>
<td><%= check_box weekends => 1, defined $off->{weekends} ? (checked => 'checked') : () %></td>
</tr>
<tr>
<td>-</td>
<td>Feriedager</td>
<td><%= text_field vacation_days => 0, size => 2, class => 'text-field', autocomplete => 'off' %></td>
<td>&#160;</td>
</tr>
<tr>
<td>-</td>
<td>Hellig- og høytidsdager</td>
<td><%= $off->{holiday} || 0 %></td>
<td>&#160;</td>
</tr>
<tr>
<td>-</td>
<td>Fri i påsken</td>
<td><%= $off->{easter} || 0 %></td>
<td><%= check_box easter => 1, defined $off->{easter} ? (checked => 'checked') : () %></td>
</tr>
<tr>
<td>-</td>
<td>Fri i julen</td>
<td><%= $off->{christmas} || 0 %></td>
<td><%= check_box christmas => 1, defined $off->{christmas} ? (checked => 'checked') : () %></td>
</tr>
</tbody>
<tfoot>
<tr style="border-top:1px solid #000;">
<td>=</td>
<td>Arbeidsdager</td>
<td title="<%= 7.5 * ($days - $off->{total}) %> timer"><%= $days - $off->{total} %></td>
<td><%= submit_button 'Oppdater', class => "btn" %></td>
</tr>
</tfoot>
</table>
% end
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment