Вот комплексное решение для возврата DateTimeSpan
, похожего на TimeSpan
, за исключением того, что оно включает в себя все компоненты даты в дополнение к компонентам времени.
Использование:
void Main()
{
DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
var dateSpan = DateTimeSpan.CompareDates(compareTo, now);
Console.WriteLine("Years: " + dateSpan.Years);
Console.WriteLine("Months: " + dateSpan.Months);
Console.WriteLine("Days: " + dateSpan.Days);
Console.WriteLine("Hours: " + dateSpan.Hours);
Console.WriteLine("Minutes: " + dateSpan.Minutes);
Console.WriteLine("Seconds: " + dateSpan.Seconds);
Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds);
}
Выходы:
Years: 1 Months: 5 Days: 27 Hours: 1 Minutes: 36 Seconds: 50 Milliseconds: 0
blockquote>Для удобства я включил логику в структуру
DateTimeSpan
, но вы можете перемещать методCompareDates
, где бы вы ни находились. Также обратите внимание: не имеет значения, какая дата предшествует другой.public struct DateTimeSpan { private readonly int years; private readonly int months; private readonly int days; private readonly int hours; private readonly int minutes; private readonly int seconds; private readonly int milliseconds; public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds) { this.years = years; this.months = months; this.days = days; this.hours = hours; this.minutes = minutes; this.seconds = seconds; this.milliseconds = milliseconds; } public int Years { get { return years; } } public int Months { get { return months; } } public int Days { get { return days; } } public int Hours { get { return hours; } } public int Minutes { get { return minutes; } } public int Seconds { get { return seconds; } } public int Milliseconds { get { return milliseconds; } } enum Phase { Years, Months, Days, Done } public static DateTimeSpan CompareDates(DateTime date1, DateTime date2) { if (date2 < date1) { var sub = date1; date1 = date2; date2 = sub; } DateTime current = date1; int years = 0; int months = 0; int days = 0; Phase phase = Phase.Years; DateTimeSpan span = new DateTimeSpan(); int officialDay = current.Day; while (phase != Phase.Done) { switch (phase) { case Phase.Years: if (current.AddYears(years + 1) > date2) { phase = Phase.Months; current = current.AddYears(years); } else { years++; } break; case Phase.Months: if (current.AddMonths(months + 1) > date2) { phase = Phase.Days; current = current.AddMonths(months); if (current.Day < officialDay && officialDay <= DateTime.DaysInMonth(current.Year, current.Month)) current = current.AddDays(officialDay - current.Day); } else { months++; } break; case Phase.Days: if (current.AddDays(days + 1) > date2) { current = current.AddDays(days); var timespan = date2 - current; span = new DateTimeSpan(years, months, days, timespan.Hours, timespan.Minutes, timespan.Seconds, timespan.Milliseconds); phase = Phase.Done; } else { days++; } break; } } return span; } }
Делая это:
blockquote>df1 = df1["Overall Value"].str.split(...)
вы не обновляете существующий фрейм данных, но создаете новый и указываете имя
df1
на это.
df1
теперь больше не относится к исходному фрейму данных, поэтомуdf[2]
(иdf[3]
) не существует, о чемKeyError: 2
говорит вам.Вместо этого вы должны использовать другое имя для временного фрейма данных, а затем использовать его для обновления столбцов в исходном.
Кроме того, вместо того, чтобы сначала создавать два новых столбца, чтобы сразу отбросить один из них, вы должны просто использовать тот, который вам действительно нужен.
Для оставшихся столбцов, которые уже существуют, вы должны использовать индексы 1 и 2 вместо 2 и 3, но, поскольку они уже содержатся в
df1
, нет необходимости «вставлять» их заново.Примерно так:
ids_ips = df1["Overall Value"].str.split(" ", n = 1, expand = True) df1["ID"] = ids_ips[0] # df1["IP2"] = ids_ips[1] <-- don't do this df1["Time"] = df1[1] # this is probably not necessary, too df1["IP"] = df1[2] # neither is this