Skip to content

Instantly share code, notes, and snippets.

@Dracovian

Dracovian/pytime.cc

Last active Feb 18, 2020
Embed
What would you like to do?
Incomplete C++ stuff for ArchAlessus
#ifdef __cplusplus
#include <cstdio>
#include <cstdlib>
#include <ctime>
/*
* We're not going to bother to extern "C" this whole file despite that
* being the preferred route to take when writing code that can be compiled
* as C or C++.
*
* The reasoning behind this is that I am trying to avoid making a habit of
* using extern "C" where I can, just to spare the linker. We are going to
* keep as much control over the memory as we can, while we can.
*
* To accomplish something similar to extern "C", we are going to tell the
* C++ compiler that this script is going to recognize any functions and
* classes belonging to the standard namespace. Normally this would be seen
* as bad practice; but since C doesn't do function overloading, this will
* be a rather nice way to make our code C and C++ compatible without the
* use of extern "C".
*/
using namespace std;
#else
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* Create a simple boolean data type */
typedef enum { false, true } bool;
#endif
/*
* It's time to create some macros that will be used in our time format strings.
*
* %Y will be seen as the zero-padded year.
* %y will be seen as the non zero-padded year.
*
* %M will be seen as the zero-padded month.
* %m will be seen as the non zero-padded month.
*
* %D will be seen as the zero-padded day.
* %d will be seen as the non zero-padded day.
*
* %H will be seen as the zero-padded hour.
* %h will be seen as the non zero-padded hour.
*
* %I will be seen as the zero-padded minute.
* %i will be seen as the non zero-padded minute.
*
* %S will be seen as the zero-padded second.
* %s will be seen as the non zero-padded second.
*
* %p will be used as the flag for 12-hour time (A.M or P.M).
* %G will not exist because reasons pertaining to KEKW
*/
#define YEAR_PADDED "%Y"
#define MONTH_PADDED "%M"
#define DAY_PADDED "%D"
#define HOUR_PADDED "%H"
#define MINUTE_PADDED "%I"
#define SECOND_PADDED "%S"
#define YEAR_UNPADDED "%y"
#define MONTH_UNPADDED "%m"
#define DAY_UNPADDED "%d"
#define HOUR_UNPADDED "%h"
#define MINUTE_UNPADDED "%i"
#define SECOND_UNPADDED "%s"
#define TWELVE_HOUR_FLAG "%p"
/*
* The reasoning behind bit fields in our time structure is to hopefully force
* better memory management because we don't need any value larger than 11 bits
* in width in any of our structure variables.
*
* Also I'm going to cut off the year at 2047 because we will be running out of
* 32-bit UNIX time in 2038, almost 10 years before we will even reach the year
* 2047.
*/
typedef struct {
unsigned short
tm_year : 11, /* year from 0000 to 2047 */
tm_mon : 4, /* month from 00 to 15 */
tm_mday : 5, /* date from 00 to 31 */
tm_hour : 5, /* hour from 00 to 31 */
tm_min : 6, /* minute from 00 to 63 */
tm_sec : 6, /* seconds from 00 to 63 */
tm_wday : 3, /* weekday from 00 to 07 */
tm_yday : 9, /* yearday from 000 to 511 */
tm_zone : 5; /* timezone from 00 to 31 */
} struct_time;
/*
* We will need a function that determines the month based on the day of the
* year. This will be an ugly looking function but it should serve an important
* function to our program.
*/
void get_month_by_date(struct_time *tim, unsigned short day, bool leap_year) {
/* Return January if we're less than 32 days in the year */
if (day < 32) {
tim->tm_mday = day;
tim->tm_mon = 1;
return;
}
int offsets[12] = {
leap_year ? 335 : 334, /* December */
leap_year ? 305 : 304, /* November */
leap_year ? 274 : 273, /* October */
leap_year ? 244 : 243, /* September */
leap_year ? 213 : 212, /* August */
leap_year ? 182 : 181, /* July */
leap_year ? 152 : 151, /* June */
leap_year ? 121 : 120, /* May */
leap_year ? 91 : 90, /* April */
leap_year ? 60 : 59, /* March */
leap_year ? 31 : 31, /* February */
leap_year ? 0 : 0, /* January */
};
unsigned month = 12;
for (unsigned i = 0; i < 11; i++) {
month--;
if (day <= offsets[i] && day > offsets[i+1]) {
tim->tm_mday = day - offsets[i+1];
tim->tm_mon = month;
return;
}
}
}
/*
* We will need a function that takes a timestamp and outputs our time structure
* which will come in handy for when we want to print out a human-readable date
* at some point in the code.
*
* The timestamp will not include the milliseconds since that doesn't fit within
* the constraints of a 32-bit integer type.
*
* The beginning of our timestamp will be January 1, 1970 00:00:00 UTC-0
* We can't effectively represent half-hour or quarter-hour timezones with this
* system, but we can get by this with a few cheeky workarounds.
*
* Here's how we will break down the timestamp:
*
* Since a year contains approximately 365.25 days (the .25 days accomodates
* the leap years that happens once every 4 years) we can't make use of that
* in our methodology due to integers not natively supporting any value that
* isn't a whole number (it would simply round it down to 365 if we tried).
*
* So in order to effectively break down our timestamp, we will have to work by
* determining how many minutes, hours, days or weeks it has been since 1970.
* Doing this will give us the best idea on what year we're dealing with in
* the timestamp.
*
* minutes = timestamp / 60
* hours = timestamp / 3600
* days = timestamp / 86400
* weeks = timestamp / 604800
*
* From there we can figure out a few things based on the starting point:
* 1970 was not a leap year, so the number of days in 1970 would be roughly
* 365 days. From that inferrence we can easily determine if a timestamp takes
* place in a leap year based on knowing that the first leap year will occur
* in 1972 for our 32-bit epoch.
*
* The Gregorian calendar has a static number of days for 11 of the 12 months
* excluding February which has 29 days in a leap year rather than 28 days.
* This means that if our timestamp takes place after 31 days into the year
* then we're going to have to determine if we have a leap year when setting
* the day of the month in our time structure.
*
* We will be starting off our week on a Sunday and ending off our week on a
* Saturday. A timestamp of 63072000 would be the first day of 1972 which is
* a known leap year. From there we can check if the year minus 1972 returns
* 0 when applying a modulo of 4 to it.
*/
struct_time get_time(const unsigned int timestamp) {
/* Initialize our output variable */
struct_time t;
/* It's relatively easy to get the year from a timestamp */
t.tm_year = 1970 + (timestamp / 31557600);
/* Now we can store a manipulated version of our timestamp */
unsigned int modded_timestamp = timestamp - (31557600 * (t.tm_year - 1970));
/* From our modified timestamp we can easily determine the day and week */
t.tm_yday = (modded_timestamp / 86400) + 1;
modded_timestamp -= (modded_timestamp / 86400) * 86400;
/* Now we need to figure out what month it is based on the year and day */
bool is_leap_year = t.tm_year >= 1972 && (t.tm_year - 1972) % 4 == 0;
get_month_by_date(&t, t.tm_yday, is_leap_year);
/* Now to finish we need to figure out the hour, minute, and second */
t.tm_hour = modded_timestamp / 3600;
modded_timestamp -= t.tm_hour * 3600;
t.tm_min = modded_timestamp / 60;
modded_timestamp -= t.tm_min * 60;
t.tm_sec = modded_timestamp;
/* Return our output variable */
return t;
}
/*
* Introduce our entrypoint function.
*/
int main(int argc, char **argv) {
unsigned int timestamp;
if (argc < 2)
timestamp = (unsigned int) time(NULL);
else
timestamp = strtoul(argv[1], NULL, 10);
struct_time t = get_time(timestamp);
fprintf(stdout, "\n%02d/%02d/%04d %02d:%02d:%02d GMT\n",
t.tm_mday, t.tm_mon, t.tm_year,
t.tm_hour, t.tm_min, t.tm_sec
);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.