long list of timezones
This commit is contained in:
parent
4c986119f9
commit
0c6003a894
|
@ -0,0 +1,13 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var $ = function(sel, el) {
|
||||||
|
return (el || window.document).querySelector(sel);
|
||||||
|
};
|
||||||
|
$.create = function(html) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.innerHTML = html;
|
||||||
|
return div;
|
||||||
|
};
|
||||||
|
var $$ = function(sel, el) {
|
||||||
|
return (el || window.document).querySelectorAll(sel);
|
||||||
|
};
|
|
@ -0,0 +1,301 @@
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// AJ Query
|
||||||
|
var $ = window.$;
|
||||||
|
var $$ = window.$$;
|
||||||
|
|
||||||
|
var state = {};
|
||||||
|
|
||||||
|
var $grantTpl;
|
||||||
|
var $devTpl;
|
||||||
|
var $updateTpl;
|
||||||
|
var $headerTpl;
|
||||||
|
var $webhookTpl;
|
||||||
|
var $webhookHeaderTpl;
|
||||||
|
|
||||||
|
// TODO add offset based on date selected (i.e. MDT -0500)
|
||||||
|
var tzdb = [
|
||||||
|
'America/New_York',
|
||||||
|
'America/Chicago',
|
||||||
|
'America/Denver',
|
||||||
|
'America/Phoenix',
|
||||||
|
'America/Los_Angeles',
|
||||||
|
'America/Sao_Paulo',
|
||||||
|
'Europe/London',
|
||||||
|
'Europe/Berlin',
|
||||||
|
'Europe/Moscow',
|
||||||
|
'Asia/Dubai',
|
||||||
|
'Asia/Kolkata',
|
||||||
|
'Asia/Hong_Kong',
|
||||||
|
'Asia/Tokyo',
|
||||||
|
'Pacific/Auckland',
|
||||||
|
'Australia/Sydney'
|
||||||
|
];
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
$headerTpl = $('.js-new-webhook .js-header').outerHTML;
|
||||||
|
|
||||||
|
$webhookHeaderTpl = $('.js-schedule .js-webhook .js-header').outerHTML;
|
||||||
|
$('.js-schedule .js-webhooks .js-headers').innerHTML = '';
|
||||||
|
$webhookTpl = $('.js-schedule .js-webhook').outerHTML;
|
||||||
|
$('.js-schedule .js-webhooks').innerHTML = '';
|
||||||
|
|
||||||
|
// after blanking all inner templates
|
||||||
|
$devTpl = $('.js-schedule').outerHTML;
|
||||||
|
|
||||||
|
console.log('hello');
|
||||||
|
|
||||||
|
$('body').addEventListener('click', function(ev) {
|
||||||
|
if (ev.target.matches('.js-new-header')) {
|
||||||
|
newWebhookHeader(ev.target);
|
||||||
|
} else if (ev.target.matches('.js-rm-header')) {
|
||||||
|
rmWebhookHeader(ev.target);
|
||||||
|
} else if (
|
||||||
|
ev.target.matches('.js-delete') &&
|
||||||
|
ev.target.closest('.js-grant')
|
||||||
|
) {
|
||||||
|
deleteGrant(ev.target.closest('.js-grant'));
|
||||||
|
} else if (
|
||||||
|
ev.target.matches('.js-delete') &&
|
||||||
|
ev.target.closest('.js-webhook')
|
||||||
|
) {
|
||||||
|
deleteWebhook(ev.target.closest('.js-webhook'));
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('body').addEventListener('submit', function(ev) {
|
||||||
|
if (ev.target.matches('.js-new-schedule')) {
|
||||||
|
newSchedule(ev.target);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function newSchedule() {
|
||||||
|
var $hook = $('.js-new-webhook');
|
||||||
|
var deviceId = $hook.closest('.js-schedule').querySelector('.js-id').value;
|
||||||
|
var hook = {
|
||||||
|
comment: $('.js-comment', $hook).value,
|
||||||
|
method: $('.js-method', $hook).value,
|
||||||
|
url: $('.js-url', $hook).value,
|
||||||
|
headers: {}
|
||||||
|
};
|
||||||
|
$$('.js-header', $hook).forEach(function($head) {
|
||||||
|
var key = $('.js-key', $head).value;
|
||||||
|
var val = $('.js-value', $head).value;
|
||||||
|
if (key && val) {
|
||||||
|
hook.headers[key] = val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hook.body = $('.js-body-template', $hook).value;
|
||||||
|
// TODO update on template change and show preview
|
||||||
|
|
||||||
|
var opts = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
Authorization: JSON.parse(localStorage.getItem('session')).access_token,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(hook),
|
||||||
|
cors: true
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
state.account.devices
|
||||||
|
.filter(function(d) {
|
||||||
|
return d.accessToken == deviceId;
|
||||||
|
})[0]
|
||||||
|
.webhooks.push(hook);
|
||||||
|
|
||||||
|
displayAccount(state.account);
|
||||||
|
return;
|
||||||
|
*/
|
||||||
|
|
||||||
|
window
|
||||||
|
.fetch('/api/iot/devices/' + deviceId + '/webhooks', opts)
|
||||||
|
.then(function(resp) {
|
||||||
|
return resp
|
||||||
|
.json()
|
||||||
|
.then(function(data) {
|
||||||
|
if (!data.webhook) {
|
||||||
|
throw new Error('something bad happened');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.account.devices
|
||||||
|
.filter(function(d) {
|
||||||
|
return d.accessToken == deviceId;
|
||||||
|
})[0]
|
||||||
|
.webhooks.push(resp.data.webhook);
|
||||||
|
|
||||||
|
displayAccount(state.account);
|
||||||
|
})
|
||||||
|
.catch(function(e) {
|
||||||
|
window.alert(e.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function newWebhookHeader($newHeader) {
|
||||||
|
var $hs = $newHeader.closest('.js-headers');
|
||||||
|
var $h = $newHeader.closest('.js-header');
|
||||||
|
var $div = document.createElement('div');
|
||||||
|
$div.innerHTML = $headerTpl;
|
||||||
|
$hs.append($('.js-header', $div));
|
||||||
|
$newHeader.hidden = true;
|
||||||
|
$('.js-rm-header', $h).hidden = false;
|
||||||
|
$('.js-key', $h).required = 'required';
|
||||||
|
$('.js-value', $h).required = 'required';
|
||||||
|
}
|
||||||
|
|
||||||
|
function rmWebhookHeader($rmHeader) {
|
||||||
|
var $h = $rmHeader.closest('.js-header');
|
||||||
|
$h.parentElement.removeChild($h);
|
||||||
|
}
|
||||||
|
function deleteWebhook($hook) {
|
||||||
|
var deviceId = $hook.closest('.js-schedule').querySelector('.js-id').value;
|
||||||
|
var id = $('.js-id', $hook).innerText;
|
||||||
|
var opts = {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
Authorization: JSON.parse(localStorage.getItem('session')).access_token
|
||||||
|
},
|
||||||
|
cors: true
|
||||||
|
};
|
||||||
|
window
|
||||||
|
.fetch('/api/iot/devices/' + deviceId + '/webhooks/' + id, opts)
|
||||||
|
.then(function(resp) {
|
||||||
|
return resp.json().then(function(result) {
|
||||||
|
if (!result.webhook) {
|
||||||
|
console.error(result);
|
||||||
|
window.alert('something went wrong: ' + JSON.stringify(result));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var index = -1;
|
||||||
|
var dev = state.account.devices.filter(function(d, i) {
|
||||||
|
return d.accessToken == deviceId;
|
||||||
|
})[0];
|
||||||
|
dev.webhooks.some(function(g, i) {
|
||||||
|
if (g.id === id) {
|
||||||
|
index = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (index > -1) {
|
||||||
|
dev.webhooks.splice(index, 1);
|
||||||
|
displayAccount(state.account);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayAccount(data) {
|
||||||
|
state.account = data;
|
||||||
|
console.log('[debug] Display Account:');
|
||||||
|
console.log(data);
|
||||||
|
var $devs = $('.js-schedules');
|
||||||
|
$devs.innerHTML = '';
|
||||||
|
data.devices.forEach(function(d) {
|
||||||
|
var $dev = $.create($devTpl);
|
||||||
|
$('.js-ieme', $dev).innerText = d.id;
|
||||||
|
$('.js-id', $dev).value = d.accessToken;
|
||||||
|
$('.js-update-url', $dev).innerText = d.updateUrl;
|
||||||
|
d.webhooks.forEach(function(h) {
|
||||||
|
var $hook = $.create($webhookTpl);
|
||||||
|
$('.js-id', $hook).innerText = h.id;
|
||||||
|
$('.js-comment', $hook).innerText = h.comment;
|
||||||
|
$('.js-method', $hook).innerText = h.method;
|
||||||
|
$('.js-url', $hook).innerText = h.url;
|
||||||
|
Object.keys(h.headers).forEach(function(k) {
|
||||||
|
var $header = $.create($webhookHeaderTpl);
|
||||||
|
var v = h.headers[k];
|
||||||
|
$('.js-key', $header).innerText = k;
|
||||||
|
$('.js-value', $header).innerText = v;
|
||||||
|
$('.js-headers', $hook).innerHTML += $header.innerHTML;
|
||||||
|
});
|
||||||
|
$('.js-body-template', $hook).innerText = h.body;
|
||||||
|
$('.js-webhooks', $dev).innerHTML += $hook.innerHTML;
|
||||||
|
});
|
||||||
|
d.grants.forEach(function(g) {
|
||||||
|
var $grant = $.create($grantTpl);
|
||||||
|
$('.js-id', $grant).innerText = g.id;
|
||||||
|
$('.js-comment', $grant).innerText = g.comment;
|
||||||
|
$('.js-token', $grant).innerText = g.token;
|
||||||
|
//TODO Math.floor(Date.now() / 1000);
|
||||||
|
var url =
|
||||||
|
'https://test.therootcompany.com/api/v1/devices/' +
|
||||||
|
d.accessToken +
|
||||||
|
'/updates?since=' +
|
||||||
|
0;
|
||||||
|
$('.js-example-curl .js-example-url', $grant).innerText = url;
|
||||||
|
$('.js-example-curl .js-example-token', $grant).innerText = g.token;
|
||||||
|
$('.js-example-js .js-example-url', $grant).innerText = url;
|
||||||
|
$('.js-example-js .js-example-id', $grant).innerText = d.accessToken;
|
||||||
|
$('.js-example-js .js-example-token', $grant).innerText = g.token;
|
||||||
|
$('.js-grants', $dev).innerHTML += $grant.innerHTML;
|
||||||
|
});
|
||||||
|
d.updates.slice(0, 10).forEach(function(u) {
|
||||||
|
var $update = $.create($updateTpl);
|
||||||
|
$('.js-update-details', $update).innerText = JSON.stringify(u);
|
||||||
|
$('.js-updates', $dev).innerHTML += $update.innerHTML;
|
||||||
|
});
|
||||||
|
$devs.innerHTML += $dev.innerHTML;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.info('[tzdb] requesting');
|
||||||
|
window.fetch('./tzdb.json').then(function(resp) {
|
||||||
|
return resp.json().then(function(tzdb) {
|
||||||
|
console.info('[tzdb] received');
|
||||||
|
var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
|
var options = $$('.js-schedule-tz option');
|
||||||
|
var valOpt = options[0].outerHTML; // UTC
|
||||||
|
var spaceOpt = options[1].outerHTML; // ----
|
||||||
|
var innerHTML = $('.js-schedule-tz').innerHTML;
|
||||||
|
innerHTML =
|
||||||
|
'<option selected value="' +
|
||||||
|
tz +
|
||||||
|
'"> ' +
|
||||||
|
tz +
|
||||||
|
'</option>' +
|
||||||
|
spaceOpt +
|
||||||
|
innerHTML.replace(/>UTC/, '> UTC');
|
||||||
|
//$('.js-schedule-tz').innerHTML += spaceOpt;
|
||||||
|
//$('.js-schedule-tz').innerHTML += valOpt.replace(/UTC/g, 'custom');
|
||||||
|
Object.keys(tzdb)
|
||||||
|
.sort()
|
||||||
|
.forEach(function(k) {
|
||||||
|
var parts = k.split(' ');
|
||||||
|
//var sep = '── ' + parts[0];
|
||||||
|
var sep = parts[0];
|
||||||
|
if (parts[0] !== parts[1]) {
|
||||||
|
sep += ' / ' + parts[1] + ' (DST)';
|
||||||
|
}
|
||||||
|
//innerHTML += '<option disabled>' + sep + '</option>';
|
||||||
|
innerHTML += '<optgroup label="' + sep + '">';
|
||||||
|
var areas = tzdb[k];
|
||||||
|
areas.forEach(function(_tz) {
|
||||||
|
if (tz !== _tz) {
|
||||||
|
innerHTML += valOpt.replace(/UTC/g, _tz);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
innerHTML += '</optgroup>';
|
||||||
|
});
|
||||||
|
$('.js-schedule-tz').innerHTML = innerHTML;
|
||||||
|
|
||||||
|
console.info('[tzdb] loaded');
|
||||||
|
run();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
//window.addEventListener('load', run);
|
||||||
|
})();
|
|
@ -4,7 +4,9 @@
|
||||||
<title>Go Again</title>
|
<title>Go Again</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Hello, World!</h1>
|
<h1>Go Again</h1>
|
||||||
|
<h2>Webhooks, on time!</h2>
|
||||||
|
|
||||||
<form class="js-schedules-list">
|
<form class="js-schedules-list">
|
||||||
<label
|
<label
|
||||||
>Token:
|
>Token:
|
||||||
|
@ -12,33 +14,153 @@
|
||||||
</label>
|
</label>
|
||||||
<button>See Schedules</button>
|
<button>See Schedules</button>
|
||||||
</form>
|
</form>
|
||||||
<pre><code class="js-schedules"> </code></pre>
|
|
||||||
|
<pre><code class="js-schedules-output"> </code></pre>
|
||||||
|
|
||||||
|
<div class="js-schedules">
|
||||||
|
<h2>Schedules</h2>
|
||||||
|
<div class="js-schedule">
|
||||||
|
<form class="js-new-schedule">
|
||||||
|
<label>Date: <input type="date" required/></label>
|
||||||
|
<br />
|
||||||
|
<label>Time: <input type="time" step="60" required/></label>
|
||||||
|
<br />
|
||||||
|
<!-- TODO combo box -->
|
||||||
|
<select class="js-schedule-tz">
|
||||||
|
<option value="UTC">UTC</option>
|
||||||
|
<option disabled>──────────</option>
|
||||||
|
</select>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<div class="doc-webhooks-container">
|
||||||
|
<h3>Webhook</h3>
|
||||||
|
<div class="js-webhooks">
|
||||||
|
<div class="js-webhook">
|
||||||
|
<h4>
|
||||||
|
<span class="js-comment"></span
|
||||||
|
><button class="js-delete" type="button">Delete</button>
|
||||||
|
</h4>
|
||||||
|
<span class="js-id" hidden></span>
|
||||||
|
<span class="js-method"></span>
|
||||||
|
<span class="js-url"></span>
|
||||||
|
<br />
|
||||||
|
<div class="js-headers">
|
||||||
|
<div class="js-header">
|
||||||
|
<span class="js-key"></span>
|
||||||
|
<span class="js-value"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<pre><code class="js-body-template"></code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="js-new-webhook">
|
||||||
|
<select class="js-template">
|
||||||
|
<option value="" selected>Custom</option>
|
||||||
|
<option value="dweet-v2">Dweet v2</option>
|
||||||
|
</select>
|
||||||
|
<br />
|
||||||
|
<input
|
||||||
|
class="js-comment"
|
||||||
|
type="text"
|
||||||
|
placeholder="Webhook Name"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<select class="js-method">
|
||||||
|
<option value="POST" selected>POST</option>
|
||||||
|
<option value="PUT">PUT</option>
|
||||||
|
</select>
|
||||||
|
<input
|
||||||
|
placeholder="https://example.com/api/v1/updates"
|
||||||
|
class="js-url"
|
||||||
|
type="url"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<div class="js-headers">
|
||||||
|
<div class="js-header">
|
||||||
|
<input placeholder="Header" class="js-key" type="text" />
|
||||||
|
<input placeholder="Value" class="js-value" type="text" />
|
||||||
|
<button type="button" class="js-rm-header" hidden>[x]</button>
|
||||||
|
<button type="button" class="js-new-header">[+]</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="js-body">
|
||||||
|
<textarea
|
||||||
|
placeholder="Body template, use '{{ keyname }}' for template values."
|
||||||
|
class="js-body-template"
|
||||||
|
></textarea>
|
||||||
|
<!-- TODO preview template -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<button class="js-create">Save Schedule</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="./ajquery.js"></script>
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var allSchedules = [];
|
||||||
document.body.addEventListener('submit', function(ev) {
|
document.body.addEventListener('submit', function(ev) {
|
||||||
if (ev.target.matches('.js-schedules-list')) {
|
if (ev.target.matches('.js-schedules-list')) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
getSchedules();
|
getSchedules();
|
||||||
|
return;
|
||||||
|
} else if (ev.target.matches('.js-schedules-new')) {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
scheduleTask();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getToken() {
|
||||||
|
return document.querySelector('.js-auth-token').value;
|
||||||
|
}
|
||||||
|
|
||||||
function getSchedules() {
|
function getSchedules() {
|
||||||
var token = document.querySelector('.js-auth-token').value;
|
return window
|
||||||
window
|
|
||||||
.fetch('/api/schedules', {
|
.fetch('/api/schedules', {
|
||||||
headers: { Authorization: token }
|
headers: { Authorization: getToken() }
|
||||||
})
|
})
|
||||||
.then(function(resp) {
|
.then(function(resp) {
|
||||||
return resp.json().then(function(schedules) {
|
return resp.json().then(function(schedules) {
|
||||||
|
allSchedules = schedules;
|
||||||
|
renderSchedules(schedules);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSchedules(schedules) {
|
||||||
document.querySelector(
|
document.querySelector(
|
||||||
'.js-schedules'
|
'.js-schedules-output'
|
||||||
).innerText = JSON.stringify(schedules, null, 2);
|
).innerText = JSON.stringify(schedules, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleTask() {
|
||||||
|
return window
|
||||||
|
.fetch('/api/schedules/new', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: getToken(),
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(task)
|
||||||
|
})
|
||||||
|
.then(function(resp) {
|
||||||
|
return resp.json().then(function(schedule) {
|
||||||
|
console.log('New Schedule:', schedule);
|
||||||
|
allSchedules.push(schedule);
|
||||||
|
renderSchedules(allSchedules);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<script src="./hooks.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
{"+00:00 +00:00":["Africa/Abidjan","Africa/Accra","Africa/Bissau","Africa/Monrovia","America/Danmarkshavn","Atlantic/Reykjavik"],
|
||||||
|
"+01:00 +01:00":["Africa/Algiers","Africa/Casablanca","Africa/Lagos","Africa/Ndjamena","Africa/Tunis"],
|
||||||
|
"+02:00 +02:00":["Africa/Cairo","Africa/Johannesburg","Africa/Khartoum","Africa/Maputo","Africa/Tripoli","Africa/Windhoek","Asia/Famagusta","Europe/Kaliningrad"],
|
||||||
|
"+01:00 +02:00":["Africa/Ceuta","Europe/Amsterdam","Europe/Andorra","Europe/Belgrade","Europe/Berlin","Europe/Brussels","Europe/Budapest","Europe/Copenhagen","Europe/Gibraltar","Europe/Luxembourg","Europe/Madrid","Europe/Malta","Europe/Monaco","Europe/Oslo","Europe/Paris","Europe/Prague","Europe/Rome","Europe/Stockholm","Europe/Tirane","Europe/Vienna","Europe/Warsaw","Europe/Zurich"],
|
||||||
|
"+00:00 +01:00":["Africa/El_Aaiun","Atlantic/Canary","Atlantic/Faroe","Atlantic/Madeira","Europe/Dublin","Europe/Lisbon","Europe/London"],
|
||||||
|
"+03:00 +03:00":["Africa/Juba","Africa/Nairobi","Antarctica/Syowa","Asia/Baghdad","Asia/Qatar","Asia/Riyadh","Europe/Istanbul","Europe/Kirov","Europe/Minsk","Europe/Moscow","Europe/Simferopol"],
|
||||||
|
"−10:00 −09:00":["America/Adak"],
|
||||||
|
"−09:00 −08:00":["America/Anchorage","America/Juneau","America/Metlakatla","America/Nome","America/Sitka","America/Yakutat"],
|
||||||
|
"−03:00 −03:00":["America/Araguaina","America/Argentina/Buenos_Aires","America/Argentina/Catamarca","America/Argentina/Cordoba","America/Argentina/Jujuy","America/Argentina/La_Rioja","America/Argentina/Mendoza","America/Argentina/Rio_Gallegos","America/Argentina/Salta","America/Argentina/San_Juan","America/Argentina/San_Luis","America/Argentina/Tucuman","America/Argentina/Ushuaia","America/Bahia","America/Belem","America/Cayenne","America/Fortaleza","America/Maceio","America/Montevideo","America/Paramaribo","America/Punta_Arenas","America/Recife","America/Santarem","Antarctica/Palmer","Antarctica/Rothera","Atlantic/Stanley"],
|
||||||
|
"−04:00 −03:00":["America/Asuncion","America/Campo_Grande","America/Cuiaba","America/Glace_Bay","America/Goose_Bay","America/Halifax","America/Moncton","America/Santiago","America/Thule","Atlantic/Bermuda"],
|
||||||
|
"−05:00 −05:00":["America/Atikokan","America/Bogota","America/Cancun","America/Eirunepe","America/Guayaquil","America/Jamaica","America/Lima","America/Panama","America/Rio_Branco"],
|
||||||
|
"−06:00 −05:00":["America/Bahia_Banderas","America/Chicago","America/Indiana/Knox","America/Indiana/Tell_City","America/Matamoros","America/Menominee","America/Merida","America/Mexico_City","America/Monterrey","America/North_Dakota/Beulah","America/North_Dakota/Center","America/North_Dakota/New_Salem","America/Rainy_River","America/Rankin_Inlet","America/Resolute","America/Winnipeg","Pacific/Easter"],
|
||||||
|
"−04:00 −04:00":["America/Barbados","America/Blanc-Sablon","America/Boa_Vista","America/Caracas","America/Curacao","America/Guyana","America/La_Paz","America/Manaus","America/Martinique","America/Port_of_Spain","America/Porto_Velho","America/Puerto_Rico","America/Santo_Domingo"],
|
||||||
|
"−06:00 −06:00":["America/Belize","America/Costa_Rica","America/El_Salvador","America/Guatemala","America/Managua","America/Regina","America/Swift_Current","America/Tegucigalpa","Pacific/Galapagos"],
|
||||||
|
"−07:00 −06:00":["America/Boise","America/Cambridge_Bay","America/Chihuahua","America/Denver","America/Edmonton","America/Inuvik","America/Mazatlan","America/Ojinaga","America/Yellowknife"],
|
||||||
|
"−07:00 −07:00":["America/Creston","America/Dawson_Creek","America/Fort_Nelson","America/Hermosillo","America/Phoenix"],
|
||||||
|
"−08:00 −07:00":["America/Dawson","America/Los_Angeles","America/Tijuana","America/Vancouver","America/Whitehorse"],
|
||||||
|
"−05:00 −04:00":["America/Detroit","America/Grand_Turk","America/Havana","America/Indiana/Indianapolis","America/Indiana/Marengo","America/Indiana/Petersburg","America/Indiana/Vevay","America/Indiana/Vincennes","America/Indiana/Winamac","America/Iqaluit","America/Kentucky/Louisville","America/Kentucky/Monticello","America/Nassau","America/New_York","America/Nipigon","America/Pangnirtung","America/Port-au-Prince","America/Thunder_Bay","America/Toronto"],
|
||||||
|
"−03:00 −02:00":["America/Godthab","America/Miquelon","America/Sao_Paulo"],
|
||||||
|
"−02:00 −02:00":["America/Noronha","Atlantic/South_Georgia"],
|
||||||
|
"−01:00 +00:00":["America/Scoresbysund","Atlantic/Azores"],
|
||||||
|
"−03:30 −02:30":["America/St_Johns"],
|
||||||
|
"+11:00 +11:00":["Antarctica/Casey","Antarctica/Macquarie","Asia/Magadan","Asia/Sakhalin","Asia/Srednekolymsk","Pacific/Bougainville","Pacific/Efate","Pacific/Guadalcanal","Pacific/Kosrae","Pacific/Norfolk","Pacific/Noumea","Pacific/Pohnpei"],
|
||||||
|
"+07:00 +07:00":["Antarctica/Davis","Asia/Bangkok","Asia/Barnaul","Asia/Ho_Chi_Minh","Asia/Hovd","Asia/Jakarta","Asia/Krasnoyarsk","Asia/Novokuznetsk","Asia/Novosibirsk","Asia/Pontianak","Asia/Tomsk","Indian/Christmas"],
|
||||||
|
"+10:00 +10:00":["Antarctica/DumontDUrville","Asia/Ust-Nera","Asia/Vladivostok","Australia/Brisbane","Australia/Lindeman","Pacific/Chuuk","Pacific/Guam","Pacific/Port_Moresby"],
|
||||||
|
"+05:00 +05:00":["Antarctica/Mawson","Asia/Aqtau","Asia/Aqtobe","Asia/Ashgabat","Asia/Atyrau","Asia/Dushanbe","Asia/Karachi","Asia/Oral","Asia/Qyzylorda","Asia/Samarkand","Asia/Tashkent","Asia/Yekaterinburg","Indian/Kerguelen","Indian/Maldives"],
|
||||||
|
"+00:00 +02:00":["Antarctica/Troll"],
|
||||||
|
"+06:00 +06:00":["Antarctica/Vostok","Asia/Almaty","Asia/Bishkek","Asia/Dhaka","Asia/Omsk","Asia/Thimphu","Asia/Urumqi","Indian/Chagos"],
|
||||||
|
"+02:00 +03:00":["Asia/Amman","Asia/Beirut","Asia/Damascus","Asia/Gaza","Asia/Hebron","Asia/Jerusalem","Europe/Athens","Europe/Bucharest","Europe/Chisinau","Europe/Helsinki","Europe/Kiev","Asia/Nicosia","Europe/Riga","Europe/Sofia","Europe/Tallinn","Europe/Uzhgorod","Europe/Vilnius","Europe/Zaporozhye"],
|
||||||
|
"+12:00 +12:00":["Asia/Anadyr","Asia/Kamchatka","Pacific/Funafuti","Pacific/Kwajalein","Pacific/Majuro","Pacific/Nauru","Pacific/Tarawa","Pacific/Wake","Pacific/Wallis"],
|
||||||
|
"+04:00 +04:00":["Asia/Baku","Asia/Dubai","Asia/Tbilisi","Asia/Yerevan","Europe/Astrakhan","Europe/Samara","Europe/Saratov","Europe/Ulyanovsk","Europe/Volgograd","Indian/Mahe","Indian/Mauritius","Indian/Reunion"],
|
||||||
|
"+08:00 +08:00":["Asia/Brunei","Asia/Choibalsan","Asia/Hong_Kong","Asia/Irkutsk","Asia/Kuala_Lumpur","Asia/Kuching","Asia/Macau","Asia/Makassar","Asia/Manila","Asia/Shanghai","Asia/Singapore","Asia/Taipei","Asia/Ulaanbaatar","Australia/Perth"],
|
||||||
|
"+09:00 +09:00":["Asia/Chita","Asia/Dili","Asia/Jayapura","Asia/Khandyga","Asia/Pyongyang","Asia/Seoul","Asia/Tokyo","Asia/Yakutsk","Pacific/Palau"],
|
||||||
|
"+05:30 +05:30":["Asia/Colombo","Asia/Kolkata"],
|
||||||
|
"+04:30 +04:30":["Asia/Kabul"],
|
||||||
|
"+05:45 +05:45":["Asia/Kathmandu"],
|
||||||
|
"+03:30 +04:30":["Asia/Tehran"],
|
||||||
|
"+06:30 +06:30":["Asia/Yangon","Indian/Cocos"],
|
||||||
|
"−01:00 −01:00":["Atlantic/Cape_Verde"],
|
||||||
|
"+09:30 +10:30":["Australia/Adelaide","Australia/Broken_Hill"],
|
||||||
|
"+10:00 +11:00":["Australia/Currie","Australia/Hobart","Australia/Melbourne","Australia/Sydney"],
|
||||||
|
"+09:30 +09:30":["Australia/Darwin"],
|
||||||
|
"+08:45 +08:45":["Australia/Eucla"],
|
||||||
|
"+10:30 +11:00":["Australia/Lord_Howe"],
|
||||||
|
"+13:00 +14:00":["Pacific/Apia","Pacific/Tongatapu"],
|
||||||
|
"+12:00 +13:00":["Pacific/Auckland","Pacific/Fiji"],
|
||||||
|
"+12:45 +13:45":["Pacific/Chatham"],
|
||||||
|
"+13:00 +13:00":["Pacific/Enderbury","Pacific/Fakaofo"],
|
||||||
|
"−09:00 −09:00":["Pacific/Gambier"],
|
||||||
|
"−10:00 −10:00":["Pacific/Honolulu","Pacific/Rarotonga","Pacific/Tahiti"],
|
||||||
|
"+14:00 +14:00":["Pacific/Kiritimati"],
|
||||||
|
"−09:30 −09:30":["Pacific/Marquesas"],
|
||||||
|
"−11:00 −11:00":["Pacific/Niue","Pacific/Pago_Pago"],
|
||||||
|
"−08:00 −08:00":["Pacific/Pitcairn"]}
|
|
@ -0,0 +1,31 @@
|
||||||
|
// https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||||
|
|
||||||
|
var zones = [];
|
||||||
|
var zoneMap = {};
|
||||||
|
var all = document.body
|
||||||
|
.querySelector('.wikitable.sortable.jquery-tablesorter')
|
||||||
|
.querySelectorAll('tr');
|
||||||
|
all = [].slice.call(all, 1); // remove header
|
||||||
|
|
||||||
|
all.forEach(function(el) {
|
||||||
|
if (/Alias|Deprecated|Etc\//.test(el.outerText)) {
|
||||||
|
$(el).remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields = [].slice.call(el.querySelectorAll('td'));
|
||||||
|
var f = fields.map(function(td) {
|
||||||
|
return td.innerText.trim();
|
||||||
|
});
|
||||||
|
var id = f[5] + ' ' + f[6];
|
||||||
|
if (!zoneMap[id]) {
|
||||||
|
zones.push([f[2], f[5], f[6]]);
|
||||||
|
}
|
||||||
|
zoneMap[id] = zoneMap[id] || [];
|
||||||
|
zoneMap[id].push(f[2]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log(JSON.stringify(zones));
|
||||||
|
console.log('Total:', all.length);
|
||||||
|
console.log('Unique:', Object.keys(zoneMap).length);
|
||||||
|
console.log(zoneMap);
|
Loading…
Reference in New Issue