Skip to content

Instantly share code, notes, and snippets.

@martinharder
Last active November 4, 2020 22:44
Show Gist options
  • Save martinharder/a2896d6fd0864abb5db0161620e5dad1 to your computer and use it in GitHub Desktop.
Save martinharder/a2896d6fd0864abb5db0161620e5dad1 to your computer and use it in GitHub Desktop.
Wie alt bin ich heute, wie alt ist mein... Ein Widget für Scriptable. // How old am I today? How old is my... A widget for Scriptable.
// Deutsche Version
const params = args.widgetParameter ? args.widgetParameter.split(',') : null;
const dateString = params && params.length > 0 ? params[0].trim() : null;
const name = params && params.length === 2 ? params[1].trim() : null;
function calculateDateValues(dateString) {
const dob = new Date(dateString);
const now = new Date(Date.now());
const totalDays = daysBetween(dob, now);
const totalMonths = monthsDiff(dob, now);
const years = Math.floor(totalMonths / 12);
const months = totalMonths - Math.floor(years) * 12;
const daysLeft = calculateRestDays(dob, years, months);
return {
totalDays: totalDays,
totalWeeks: Math.floor(totalDays / 7),
totalMonths: totalMonths,
years: years,
months: months,
daysLeft: daysLeft,
restWeeks: Math.floor(daysLeft / 7),
restDays: daysLeft - Math.floor(daysLeft / 7) * 7
}
}
function toDays(d) {
d = d || 0;
return d / 24 / 60 / 60 / 1000;
}
function toUTC(d) {
if (!d || !d.getFullYear) {
return 0;
}
return Date.UTC(d.getFullYear(), d.getMonth(), d.getDate());
}
// Anzahl Tage zwischen zwei Daten (d1, d2: Date)
function daysBetween(d1, d2){
return toDays(toUTC(d2) - toUTC(d1));
}
function daysInMonth(m, y) {
var y = y || new Date(Date.now()).getFullYear();
return toDays(Date.UTC(y, m + 1, 1) - Date.UTC(y, m, 1));
}
function daysInYear(y) {
var y = y || new Date(Date.now()).getFullYear();
return (toDays(Date.UTC(y + 1, 0, 1) - Date.UTC(y, 0, 1)));
}
function yearsDiff(d1, d2) {
return d2.getFullYear() - d1.getFullYear();
}
function monthsDiff(d1, d2) {
let years = yearsDiff(d1, d2);
let months = (years * 12) + (d2.getMonth() - d1.getMonth());
if (d2.getDate() < d1.getDate()) {
months--;
}
return months;
}
function calculateRestDays(date, years, months) {
const day = date.getDate();
const month = date.getMonth();
const year = date.getFullYear();
const newDate = new Date(Date.UTC(year + years, month + months, day));
const now = new Date(Date.now())
return daysBetween(newDate, now)
}
function pluralize(amount, word) {
let result = word
switch (word) {
case 'Jahr':
case 'Monat':
case 'Tag':
if (amount > 1) {
result += 'e';
}
break;
case 'Woche':
if (amount > 1) {
result += 'n';
}
break;
}
return result;
}
function getTextArray(values) {
let textY, textM, textW, textD = null;
if (values.years < 1) {
if (values.totalMonths > 0) {
textM = values.totalMonths + ' ' + pluralize(values.totalMonths, 'Monat');
if (values.restWeeks > 0) {
textW = values.restWeeks + ' ' + pluralize(values.restWeeks, 'Woche');
}
if (values.restDays > 0) {
textD = values.restDays + ' ' + pluralize(values.restDays, 'Tag');
}
} else if (values.totalWeeks > 0) {
textW = values.totalWeeks + ' ' + pluralize(values.totalWeeks, 'Woche');
if (values.restDays > 0) {
textD = values.restDays + ' ' + pluralize(values.restDays, 'Tag');
}
} else if (values.totalDays > 0) {
textD = values.totalDays + ' ' + pluralize(values.totalDays, 'Tag');
}
} else {
textY = values.years + ' ' + pluralize(values.years, 'Jahr');
if (values.months > 0) {
textM = values.months + ' ' + pluralize(values.months, 'Monat');
if (values.restWeeks > 0) {
textW = values.restWeeks + ' ' + pluralize(values.restWeeks, 'Woche');
}
if (values.restDays > 0) {
textD = values.restDays + ' ' + pluralize(values.restDays, 'Tag');
}
} else if (values.restWeeks > 0) {
textW = values.restWeeks + ' ' + pluralize(values.restWeeks, 'Woche');
if (values.restDays > 0) {
textD = values.restDays + ' ' + pluralize(values.restDays, 'Tag');
}
} else if (values.restDays > 0) {
textD = values.restDays + ' ' + pluralize(values.restDays, 'Tag');
}
}
const textArray = [];
if (textY) {
textArray.push(textY);
}
if (textM) {
textArray.push(textM);
}
if (textW) {
textArray.push(textW);
}
if (textD) {
textArray.push(textD);
}
const finalTextArray = [];
switch (textArray.length) {
case 4:
finalTextArray.push(textArray[0] + ',');
finalTextArray.push(textArray[1] + ',');
finalTextArray.push(textArray[2] + ' und');
finalTextArray.push(textArray[3] + ' alt.');
break;
case 3:
finalTextArray.push(textArray[0] + ',');
finalTextArray.push(textArray[1] + ' und');
finalTextArray.push(textArray[2] + ' alt.');
break;
case 2:
finalTextArray.push(textArray[0] + ' und');
finalTextArray.push(textArray[1] + ' alt.');
break;
case 1:
finalTextArray.push(textArray[0] + ' alt.');
break;
}
return finalTextArray
}
let widget = await createWidget();
if (!config.runsInWidget) {
await widget.presentSmall();
}
Script.setWidget(widget);
Script.complete();
async function createWidget(items) {
let header, label
const widget = new ListWidget()
if(!dateString) {
const errorList = new ListWidget();
errorList.addText("Kein Geburtsdatum gefunden. Bitte als Parameter angeben");
return errorList;
}
if(!/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/.test(dateString)) {
const errorList = new ListWidget();
errorList.addText("Falsches Datumformat, bitte YYYY-MM-DD benutzen.");
return errorList;
}
const values = calculateDateValues(dateString);
const headerTitle = name ? name + ' ist heute' : 'Du bist heute'
const size = !name || (name && name.length <= 7) ? 15 : name && name.length <= 12 ? 12 : name && name.length <= 18 ? 9 : 8
header = widget.addText(headerTitle)
header.centerAlignText()
header.font = Font.mediumSystemFont(size)
widget.addSpacer()
if (values.totalDays === 0) {
label = widget.addText('neu geboren.')
label.leftAlignText()
label.font = Font.mediumSystemFont(20)
widget.addSpacer()
label = widget.addText('Willkommen!')
label.leftAlignText()
label.font = Font.mediumSystemFont(20)
} else if (values.totalDays < 0) {
label = widget.addText('noch nicht geboren.')
label.leftAlignText()
label.font = Font.mediumSystemFont(15)
widget.addSpacer()
label = widget.addText('Warte noch ' + values.totalDays * -1 + ' ' + pluralize(values.totalDays * -1, 'Tag') + '.')
label.leftAlignText()
label.font = Font.mediumSystemFont(15)
} else {
const textArray = getTextArray(values)
textArray.forEach(textRow => {
label = widget.addText(textRow)
label.leftAlignText()
label.font = Font.mediumSystemFont(15)
})
}
return widget
}
// English version
const params = args.widgetParameter ? args.widgetParameter.split(',') : null;
const dateString = params && params.length > 0 ? params[0].trim() : null;
const name = params && params.length === 2 ? params[1].trim() : null;
function calculateDateValues(dateString) {
const dob = new Date(dateString);
const now = new Date(Date.now());
const totalDays = daysBetween(dob, now);
const totalMonths = monthsDiff(dob, now);
const years = Math.floor(totalMonths / 12);
const months = totalMonths - Math.floor(years) * 12;
const daysLeft = calculateRestDays(dob, years, months);
return {
totalDays: totalDays,
totalWeeks: Math.floor(totalDays / 7),
totalMonths: totalMonths,
years: years,
months: months,
daysLeft: daysLeft,
restWeeks: Math.floor(daysLeft / 7),
restDays: daysLeft - Math.floor(daysLeft / 7) * 7
}
}
function toDays(d) {
d = d || 0;
return d / 24 / 60 / 60 / 1000;
}
function toUTC(d) {
if (!d || !d.getFullYear) {
return 0;
}
return Date.UTC(d.getFullYear(), d.getMonth(), d.getDate());
}
function daysBetween(d1, d2){
return toDays(toUTC(d2) - toUTC(d1));
}
function daysInMonth(m, y) {
var y = y || new Date(Date.now()).getFullYear();
return toDays(Date.UTC(y, m + 1, 1) - Date.UTC(y, m, 1));
}
function daysInYear(y) {
var y = y || new Date(Date.now()).getFullYear();
return (toDays(Date.UTC(y + 1, 0, 1) - Date.UTC(y, 0, 1)));
}
function yearsDiff(d1, d2) {
return d2.getFullYear() - d1.getFullYear();
}
function monthsDiff(d1, d2) {
let years = yearsDiff(d1, d2);
let months = (years * 12) + (d2.getMonth() - d1.getMonth());
if (d2.getDate() < d1.getDate()) {
months--;
}
return months;
}
function calculateRestDays(date, years, months) {
const day = date.getDate();
const month = date.getMonth();
const year = date.getFullYear();
const newDate = new Date(Date.UTC(year + years, month + months, day));
const now = new Date(Date.now())
return daysBetween(newDate, now)
}
function pluralize(amount, word) {
return amount > 1 ? word + 's' : word
}
function getTextArray(values) {
let textY, textM, textW, textD = null;
if (values.years < 1) {
if (values.totalMonths > 0) {
textM = values.totalMonths + ' ' + pluralize(values.totalMonths, 'month');
if (values.restWeeks > 0) {
textW = values.restWeeks + ' ' + pluralize(values.restWeeks, 'week');
}
if (values.restDays > 0) {
textD = values.restDays + ' ' + pluralize(values.restDays, 'day');
}
} else if (values.totalWeeks > 0) {
textW = values.totalWeeks + ' ' + pluralize(values.totalWeeks, 'week');
if (values.restDays > 0) {
textD = values.restDays + ' ' + pluralize(values.restDays, 'day');
}
} else if (values.totalDays > 0) {
textD = values.totalDays + ' ' + pluralize(values.totalDays, 'day');
}
} else {
textY = values.years + ' ' + pluralize(values.years, 'year');
if (values.months > 0) {
textM = values.months + ' ' + pluralize(values.months, 'month');
if (values.restWeeks > 0) {
textW = values.restWeeks + ' ' + pluralize(values.restWeeks, 'week');
}
if (values.restDays > 0) {
textD = values.restDays + ' ' + pluralize(values.restDays, 'day');
}
} else if (values.restWeeks > 0) {
textW = values.restWeeks + ' ' + pluralize(values.restWeeks, 'week');
if (values.restDays > 0) {
textD = values.restDays + ' ' + pluralize(values.restDays, 'day');
}
} else if (values.restDays > 0) {
textD = values.restDays + ' ' + pluralize(values.restDays, 'day');
}
}
const textArray = [];
if (textY) {
textArray.push(textY);
}
if (textM) {
textArray.push(textM);
}
if (textW) {
textArray.push(textW);
}
if (textD) {
textArray.push(textD);
}
const finalTextArray = [];
switch (textArray.length) {
case 4:
finalTextArray.push(textArray[0] + ',');
finalTextArray.push(textArray[1] + ',');
finalTextArray.push(textArray[2] + ' and');
finalTextArray.push(textArray[3] + ' old.');
break;
case 3:
finalTextArray.push(textArray[0] + ',');
finalTextArray.push(textArray[1] + ' and');
finalTextArray.push(textArray[2] + ' old.');
break;
case 2:
finalTextArray.push(textArray[0] + ' and');
finalTextArray.push(textArray[1] + ' old.');
break;
case 1:
finalTextArray.push(textArray[0] + ' old.');
break;
}
return finalTextArray
}
let widget = await createWidget();
if (!config.runsInWidget) {
await widget.presentSmall();
}
Script.setWidget(widget);
Script.complete();
async function createWidget(items) {
let header, label
const widget = new ListWidget()
if(!dateString) {
const errorList = new ListWidget();
errorList.addText("No birthday found. Please provide it as parameter");
return errorList;
}
if(!/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/.test(dateString)) {
const errorList = new ListWidget();
errorList.addText("Wrong date format, use YYYY-MM-DD please.");
return errorList;
}
const values = calculateDateValues(dateString);
const headerTitle = name ? 'Today ' + name + ' is' : 'Today you are'
const size = !name || (name && name.length <= 7) ? 15 : name && name.length <= 12 ? 12 : name && name.length <= 18 ? 9 : 8
header = widget.addText(headerTitle)
header.centerAlignText()
header.font = Font.mediumSystemFont(size)
widget.addSpacer()
if (values.totalDays === 0) {
label = widget.addText('born.')
label.leftAlignText()
label.font = Font.mediumSystemFont(20)
widget.addSpacer()
label = widget.addText('Welcome!')
label.leftAlignText()
label.font = Font.mediumSystemFont(20)
} else if (values.totalDays < 0) {
label = widget.addText('not born yet.')
label.leftAlignText()
label.font = Font.mediumSystemFont(15)
widget.addSpacer()
label = widget.addText('Wait for ' + values.totalDays * -1 + ' ' + pluralize(values.totalDays * -1, 'day') + '.')
label.leftAlignText()
label.font = Font.mediumSystemFont(15)
} else {
const textArray = getTextArray(values)
textArray.forEach(textRow => {
label = widget.addText(textRow)
label.leftAlignText()
label.font = Font.mediumSystemFont(15)
})
}
return widget
}
@martinharder
Copy link
Author

martinharder commented Nov 4, 2020

Updates

04.11.2020

  • Eine zweite Version in englischer Sprache hinzugefügt // Added new version in english language.

Beschreibung

Spätestens als ich Vater wurde, habe ich immer die Tage, Wochen und Monate gezählt, seit dem meine Kinder geboren wurden. Und besonders als sie noch Babies waren, wurde man oft gefragt, wie alt sie sind. Mit diesem Widget hat man die Antwort immer exakt parat.

Installation

Zuerst muss die App Scriptable installiert werden. Dann ein neues Script anlegen und den Code von hier kopieren und dort einfügen. Hier kann auch der Name des Scripts genannt werden, sowie Farbe und Icon (Glyph) für das Script.
Anschließend muss auf dem Homebildschirm oder dem Today-Screen ein Widget hinzugefügt werden. Als Quelle wählt man Scriptable und dann die Größe des Widgets (die kleine Größe ist ausreichend). Danach klickt man auf das Widget und hat drei Bereiche zur Bearbeitung: welchen Code aus Scriptable will man ausführen, was soll passieren, wenn man auf das Widget klickt und dann können Parameter angegeben werden.
PARAMETER: hier muss zumindest das Geburtsdatum im Format YYYY-MM-DD angegeben werden. Wer will, kann auch nach einem Komma einen Namen angeben. Beispiele:

  • 2010-01-01,Sophie
  • 1975-10-09,Martin
  • 1995-11-04

Vorschau

age-dark
age-light
age-en-dark
age-en-light

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment