Skip to content

Instantly share code, notes, and snippets.

@jfbueno
Last active February 7, 2018 11:07
Show Gist options
  • Save jfbueno/6ca90f23da1b3dc7e92959acfb049444 to your computer and use it in GitHub Desktop.
Save jfbueno/6ca90f23da1b3dc7e92959acfb049444 to your computer and use it in GitHub Desktop.
SimpleDateTimeApi
using System;
using System.Globalization;
namespace JefersonBueno
{
public class Program
{
public static string ChangeDate(string date, char op, long value)
{
var toAdd = Math.Abs(value);
if(op == '-')
toAdd *= -1;
var dt = CwiSimpleDateTimeExtensions.FromDateTimeString(date);
var newDate = dt.AddMinutes(toAdd);
return newDate.ToString();
}
public static void Main()
{
var testes = new[]
{
new { Input = "01/03/2010 23:00", Op = '+', Val = 4_000L },
new { Input = "01/01/0030 00:00", Op = '+', Val = 18_000L },
new { Input = "01/05/2018 14:00", Op = '+', Val = 50L },
new { Input = "02/08/2014 00:08", Op = '-', Val = -8L },
new { Input = "01/05/0001 00:50", Op = '-', Val = 50L }
};
foreach(var teste in testes)
{
var result = ChangeDate(teste.Input, teste.Op, teste.Val);
var toAdd = Math.Abs(teste.Val);
if(teste.Op == '-')
toAdd *= -1;
var expected = DateTime.ParseExact(teste.Input, "dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture).AddMinutes(toAdd).ToString("dd/MM/yyyy HH:mm");
Console.WriteLine($"Input: {teste.Input} {teste.Op} {teste.Val}\nResult: {result}\nExpected: {expected} | {result == expected}\n");
}
}
}
}
using System;
namespace JefersonBueno
{
/*
** Estrutura que representa uma data simples. Sem anos bissextos e fusos horários.
** Cada objeto deste tipo tem um campo chamado 'dateMillis', que contém a data e o tempo
** (horas e minutos apenas) contando em milissegundos a partir do dia 01/01/0001 às 00:00.
*/
public struct CwiSimpleDateTime
{
private enum DatePortion
{
Year, Month, Day
}
private static readonly int[] MaxDaysOfMonths = { 30, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
private static readonly int[] DaysToMonth = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
private const int DaysPerYear = 365;
private const int MillisPerSecond = 1000;
private const int MillisPerMinute = 60 * MillisPerSecond;
private const int MillisPerHour = 60 * MillisPerMinute;
private const int MillisPerDay = 24 * MillisPerHour;
private ulong dateMillis;
public int Year => GetDateFraction(DatePortion.Year);
public int Month => GetDateFraction(DatePortion.Month);
public int Day => GetDateFraction(DatePortion.Day);
public int Hour => (int)((dateMillis / MillisPerHour) % 24);
public int Minute => (int)((dateMillis / MillisPerMinute) % 60);
private CwiSimpleDateTime(ulong millis) => dateMillis = millis;
public CwiSimpleDateTime(int year, int month, int day, int hour, int minute) => dateMillis = DateToMillis(year, month, day) + (ulong)TimeToMillis(hour, minute);
public CwiSimpleDateTime(int year, int month, int day) : this(year, month, day, 0, 0) { }
public CwiSimpleDateTime AddMinutes(long minutes) => Add(minutes, MillisPerMinute);
private CwiSimpleDateTime Add(long value, int multiplier) => AddMilliseconds(value * multiplier);
private CwiSimpleDateTime AddMilliseconds(long millis) => new CwiSimpleDateTime((ulong)millis + dateMillis);
public override string ToString() => $"{Day:d2}/{Month:d2}/{Year:d4} {Hour:d2}:{Minute:d2}";
private int GetDateFraction(DatePortion part)
{
var qtDays = (int)(dateMillis / MillisPerDay);
var qtYears = qtDays / DaysPerYear;
if(part == DatePortion.Year)
return qtYears + 1;
qtDays -= qtYears * DaysPerYear; // n = dia do ano subtraindo 1, por ex.: 2018/03/03 => 62º dia; n => 61
int month = 0;
while (qtDays >= DaysToMonth[month]) {
month++;
}
if(part == DatePortion.Month)
return month;
return qtDays - DaysToMonth[month - 1] + 1;
}
private static ulong DateToMillis(int year, int month, int day)
{
if(year < 1 || year > 9999 || month < 1 || month > 12) {
throw new ArgumentOutOfRangeException("O ano precisa estar entre 1 e 9999 e o mês entre 1 e 12");
}
if(day > MaxDaysOfMonths[month - 1]) {
throw new ArgumentOutOfRangeException($"Quantidade de dias ({day}) inválida para o mês {month}");
}
int y = year - 1;
int m = month - 1;
ulong n = (ulong)((day - 1) + DaysToMonth[month - 1] + ((year - 1) * DaysPerYear));
return n * MillisPerDay;
}
private static long TimeToMillis(int hour, int minute)
{
if(hour < 0 || hour > 23 || minute < 0 || minute > 59) {
throw new ArgumentOutOfRangeException($"Intervalo inválido para horas e minutos ({hour}:{minute})");
}
int qt = (hour) * MillisPerHour + minute * MillisPerMinute;
return qt;
}
}
}
using System;
namespace JefersonBueno
{
public static class CwiSimpleDateTimeExtensions
{
public static CwiSimpleDateTime FromDateTimeString(string data)
{
var split = data.Split(' ');
var (year, month, day) = FromDateString(split[0]);
var (hour, minute) = FromTimeString(split[1]);
return new CwiSimpleDateTime(year, month, day, hour, minute);
}
private static (int year, int month, int day) FromDateString(string date)
{
var splittedDate = date.Split('/');
if(splittedDate.Length != 3)
return (0, 0, 0);
return (Convert.ToInt32(splittedDate[2]), Convert.ToInt32(splittedDate[1]), Convert.ToInt32(splittedDate[0]));
}
private static (int hour, int minute) FromTimeString(string time)
{
var splittedTime = time.Split(':');
if(splittedTime.Length != 2)
return (0, 0);
return (Convert.ToInt32(splittedTime[0]), Convert.ToInt32(splittedTime[1]));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment