SubtitleEdit/libse/TimeCode.cs

265 lines
8.9 KiB
C#
Raw Normal View History

2016-02-08 21:11:03 +01:00
using Nikse.SubtitleEdit.Core.SubtitleFormats;
using System;
using System.Globalization;
namespace Nikse.SubtitleEdit.Core
{
public class TimeCode
{
2019-09-29 14:33:26 +02:00
private static readonly char[] TimeSplitChars = { ':', ',', '.' };
2016-02-08 21:11:03 +01:00
public const double BaseUnit = 1000.0; // Base unit of time
private double _totalMilliseconds;
public bool IsMaxTime => Math.Abs(_totalMilliseconds - MaxTimeTotalMilliseconds) < 0.01;
public const double MaxTimeTotalMilliseconds = 359999999; // new TimeCode(99, 59, 59, 999).TotalMilliseconds
2016-02-08 21:11:03 +01:00
public static TimeCode FromSeconds(double seconds)
{
return new TimeCode(seconds * BaseUnit);
}
public static double ParseToMilliseconds(string text)
{
2019-09-29 14:33:26 +02:00
var parts = text.Split(TimeSplitChars, StringSplitOptions.RemoveEmptyEntries);
2016-02-08 21:11:03 +01:00
if (parts.Length == 4)
{
2019-09-29 14:33:26 +02:00
if (int.TryParse(parts[0], out var hours) && int.TryParse(parts[1], out var minutes) && int.TryParse(parts[2], out var seconds) && int.TryParse(parts[3], out var milliseconds))
2016-02-08 21:11:03 +01:00
{
return new TimeSpan(0, hours, minutes, seconds, milliseconds).TotalMilliseconds;
}
}
return 0;
}
public static double ParseHHMMSSFFToMilliseconds(string text)
{
2019-09-29 14:33:26 +02:00
var parts = text.Split(TimeSplitChars, StringSplitOptions.RemoveEmptyEntries);
2016-02-08 21:11:03 +01:00
if (parts.Length == 4)
{
2019-09-29 14:33:26 +02:00
if (int.TryParse(parts[0], out var hours) && int.TryParse(parts[1], out var minutes) && int.TryParse(parts[2], out var seconds) && int.TryParse(parts[3], out var frames))
2016-02-08 21:11:03 +01:00
{
return new TimeCode(hours, minutes, seconds, SubtitleFormat.FramesToMillisecondsMax999(frames)).TotalMilliseconds;
}
}
return 0;
}
2017-05-05 18:20:57 +02:00
public TimeCode()
{
}
2016-02-08 21:11:03 +01:00
public TimeCode(TimeSpan timeSpan)
{
_totalMilliseconds = timeSpan.TotalMilliseconds;
}
public TimeCode(double totalMilliseconds)
{
_totalMilliseconds = totalMilliseconds;
}
2016-02-27 00:35:48 +01:00
public TimeCode(int hours, int minutes, int seconds, int milliseconds)
2016-02-08 21:11:03 +01:00
{
2016-02-27 00:35:48 +01:00
_totalMilliseconds = hours * 60 * 60 * BaseUnit + minutes * 60 * BaseUnit + seconds * BaseUnit + milliseconds;
2016-02-08 21:11:03 +01:00
}
public int Hours
{
get
{
var ts = TimeSpan;
return ts.Hours + ts.Days * 24;
}
set
{
var ts = TimeSpan;
2016-11-26 19:08:52 +01:00
_totalMilliseconds = new TimeSpan(ts.Days, value, ts.Minutes, ts.Seconds, ts.Milliseconds).TotalMilliseconds;
2016-02-08 21:11:03 +01:00
}
}
public int Minutes
{
2019-09-29 14:33:26 +02:00
get => TimeSpan.Minutes;
2016-02-08 21:11:03 +01:00
set
{
var ts = TimeSpan;
2016-11-26 19:08:52 +01:00
_totalMilliseconds = new TimeSpan(ts.Days, ts.Hours, value, ts.Seconds, ts.Milliseconds).TotalMilliseconds;
2016-02-08 21:11:03 +01:00
}
}
public int Seconds
{
2019-09-29 14:33:26 +02:00
get => TimeSpan.Seconds;
2016-02-08 21:11:03 +01:00
set
{
var ts = TimeSpan;
2016-11-26 19:08:52 +01:00
_totalMilliseconds = new TimeSpan(ts.Days, ts.Hours, ts.Minutes, value, ts.Milliseconds).TotalMilliseconds;
2016-02-08 21:11:03 +01:00
}
}
public int Milliseconds
{
2019-09-29 14:33:26 +02:00
get => TimeSpan.Milliseconds;
2016-02-08 21:11:03 +01:00
set
{
var ts = TimeSpan;
2016-11-26 19:08:52 +01:00
_totalMilliseconds = new TimeSpan(ts.Days, ts.Hours, ts.Minutes, ts.Seconds, value).TotalMilliseconds;
2016-02-08 21:11:03 +01:00
}
}
public double TotalMilliseconds
{
2019-09-29 14:33:26 +02:00
get => _totalMilliseconds;
set => _totalMilliseconds = value;
2016-02-08 21:11:03 +01:00
}
public double TotalSeconds
{
2019-09-29 14:33:26 +02:00
get => _totalMilliseconds / BaseUnit;
set => _totalMilliseconds = value * BaseUnit;
2016-02-08 21:11:03 +01:00
}
public TimeSpan TimeSpan
{
2019-09-29 14:33:26 +02:00
get => TimeSpan.FromMilliseconds(_totalMilliseconds);
set => _totalMilliseconds = value.TotalMilliseconds;
2016-02-08 21:11:03 +01:00
}
2017-12-10 22:18:13 +01:00
2017-05-05 18:20:57 +02:00
public override string ToString() => ToString(false);
2016-02-08 21:11:03 +01:00
public string ToString(bool localize)
{
var ts = TimeSpan;
string decimalSeparator = localize ? CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator : ",";
2019-09-29 14:33:26 +02:00
string s = $"{ts.Hours + ts.Days * 24:00}:{ts.Minutes:00}:{ts.Seconds:00}{decimalSeparator}{ts.Milliseconds:000}";
2016-02-08 21:11:03 +01:00
return PrefixSign(s);
2016-02-08 21:11:03 +01:00
}
public string ToShortString(bool localize = false)
{
var ts = TimeSpan;
string decimalSeparator = localize ? CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator : ",";
string s;
if (ts.Minutes == 0 && ts.Hours == 0 && ts.Days == 0)
2019-01-19 14:40:37 +01:00
{
2019-09-29 14:33:26 +02:00
s = $"{ts.Seconds:0}{decimalSeparator}{ts.Milliseconds:000}";
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
else if (ts.Hours == 0 && ts.Days == 0)
2019-01-19 14:40:37 +01:00
{
2019-09-29 14:33:26 +02:00
s = $"{ts.Minutes:0}:{ts.Seconds:00}{decimalSeparator}{ts.Milliseconds:000}";
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
else
2019-01-19 14:40:37 +01:00
{
2019-09-29 14:33:26 +02:00
s = $"{ts.Hours + ts.Days * 24:0}:{ts.Minutes:00}:{ts.Seconds:00}{decimalSeparator}{ts.Milliseconds:000}";
2019-01-19 14:40:37 +01:00
}
return PrefixSign(s);
2016-02-08 21:11:03 +01:00
}
public string ToShortStringHHMMSSFF()
{
string s = ToHHMMSSFF();
string pre = string.Empty;
if (s.StartsWith('-'))
{
pre = "-";
s = s.TrimStart('-');
}
int j = 0;
2017-05-05 18:20:57 +02:00
int len = s.Length;
2017-02-23 10:06:50 +01:00
while (j + 6 < len && s[j] == '0' && s[j + 1] == '0' && s[j + 2] == ':')
{
j += 3;
2017-02-23 10:06:50 +01:00
}
s = j > 0 ? s.Substring(j) : s;
return pre + s;
2016-02-08 21:11:03 +01:00
}
public string ToHHMMSSFF()
{
string s;
2016-02-08 21:11:03 +01:00
var ts = TimeSpan;
2016-02-25 07:41:49 +01:00
var frames = Math.Round(ts.Milliseconds / (BaseUnit / Configuration.Settings.General.CurrentFrameRate));
2016-02-08 21:11:03 +01:00
if (frames >= Configuration.Settings.General.CurrentFrameRate - 0.001)
2019-01-19 14:40:37 +01:00
{
2019-12-08 21:11:34 +01:00
var newTs = new TimeSpan(ts.Ticks);
2020-01-20 08:04:41 +01:00
newTs = newTs.Add(new TimeSpan(0, 0, 1));
2019-12-08 21:11:34 +01:00
s = $"{newTs.Days * 24 + newTs.Hours:00}:{newTs.Minutes:00}:{newTs.Seconds:00}:{0:00}";
2019-01-19 14:40:37 +01:00
}
else
2019-01-19 14:40:37 +01:00
{
2019-09-29 14:33:26 +02:00
s = $"{ts.Days * 24 + ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}:{SubtitleFormat.MillisecondsToFramesMaxFrameRate(ts.Milliseconds):00}";
2019-01-19 14:40:37 +01:00
}
return PrefixSign(s);
2016-02-08 21:11:03 +01:00
}
2016-08-11 12:36:19 +02:00
public string ToSSFF()
{
string s;
var ts = TimeSpan;
var frames = Math.Round(ts.Milliseconds / (BaseUnit / Configuration.Settings.General.CurrentFrameRate));
if (frames >= Configuration.Settings.General.CurrentFrameRate - 0.001)
2019-01-19 14:40:37 +01:00
{
2019-09-29 14:33:26 +02:00
s = $"{ts.Seconds + 1:00}:{0:00}";
2019-01-19 14:40:37 +01:00
}
else
2019-01-19 14:40:37 +01:00
{
2019-09-29 14:33:26 +02:00
s = $"{ts.Seconds:00}:{SubtitleFormat.MillisecondsToFramesMaxFrameRate(ts.Milliseconds):00}";
2019-01-19 14:40:37 +01:00
}
return PrefixSign(s);
}
2016-02-08 21:11:03 +01:00
public string ToHHMMSSPeriodFF()
{
string s;
2016-02-08 21:11:03 +01:00
var ts = TimeSpan;
2016-02-25 07:41:49 +01:00
var frames = Math.Round(ts.Milliseconds / (BaseUnit / Configuration.Settings.General.CurrentFrameRate));
2016-02-08 21:11:03 +01:00
if (frames >= Configuration.Settings.General.CurrentFrameRate - 0.001)
2019-01-19 14:40:37 +01:00
{
2019-12-08 21:11:34 +01:00
var newTs = new TimeSpan(ts.Ticks);
2020-01-20 08:04:41 +01:00
newTs = newTs.Add(new TimeSpan(0, 0, 1));
2019-12-08 21:11:34 +01:00
s = $"{newTs.Days * 24 + newTs.Hours:00}:{newTs.Minutes:00}:{newTs.Seconds:00}.{0:00}";
2019-01-19 14:40:37 +01:00
}
else
2019-01-19 14:40:37 +01:00
{
2019-09-29 14:33:26 +02:00
s = $"{ts.Days * 24 + ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}.{SubtitleFormat.MillisecondsToFramesMaxFrameRate(ts.Milliseconds):00}";
2019-01-19 14:40:37 +01:00
}
return PrefixSign(s);
2016-02-08 21:11:03 +01:00
}
private string PrefixSign(string time) => TotalMilliseconds >= 0 ? time : $"-{time.RemoveChar('-')}";
2016-02-08 21:11:03 +01:00
public string ToDisplayString()
{
if (IsMaxTime)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
return "-";
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
2017-05-05 18:20:57 +02:00
if (Configuration.Settings?.General.UseTimeFormatHHMMSSFF == true)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
return ToHHMMSSFF();
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
return ToString(true);
}
public string ToShortDisplayString()
{
if (IsMaxTime)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
return "-";
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
2017-05-05 18:20:57 +02:00
if (Configuration.Settings?.General.UseTimeFormatHHMMSSFF == true)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
return ToShortStringHHMMSSFF();
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
return ToShortString(true);
}
}
}