How to convert TIME to Hours Minute - dart

I made attendance application. It will record user attendance based on location. I have field in database called duration_attendance, this field have type data TIME.
This field will record user duration attendance from start work and go home (Example : Start 08:00. End 17:00. It will return duration 08:00)
In Server Side , i can achieved it with:
Convert Time To Second : SELECT TIME_TO_SEC('05:15:40');
Convert Second To Hours minute : SELECT TIME_FORMAT(SEC_TO_TIME('48465'),'%Hh %im') // 13h 27m
How can i convert TIME to Hours and Minutes format in dart side ?
In my case , duration_attendance = 08:35 i want convert it to 8 Hours 35 Minutes.
Response API
{
"status": 1,
"message": "Data Absensi Bulan 05 Tahun 2020",
"data": [
{
"tanggal_absen": "2020-05-10",
"jam_absen_masuk": "07:55:00",
"jam_absen_pulang": "21:22:45",
"durasi_absen": "13:27:45",
"status": "o",
"durasi_lembur": "04:22:45"
},
{
"tanggal_absen": "2020-05-11",
"jam_absen_masuk": "21:15:10",
"jam_absen_pulang": "21:15:10",
"durasi_absen": "00:00:00",
"status": "a",
"durasi_lembur": "00:00:00"
},
{
"tanggal_absen": "2020-05-12",
"jam_absen_masuk": "21:13:01",
"jam_absen_pulang": "21:13:01",
"durasi_absen": "00:00:00",
"status": "a",
"durasi_lembur": "00:00:00"
}
]
}

My Temporary Solution to my case.
Work with Format time xx:xx:xx
enum TimeFormat { Jam, JamMenit, JamMenitDetik, Menit, MenitDetik, Detik }
String formatTimeTo(
String time, {
TimeFormat timeFormat,
}) {
String hour = time.replaceAll(":", "").substring(0, 2);
String minute = time.replaceAll(":", "").substring(2, 4);
String second = time.replaceAll(":", "").substring(4, 6);
String resultHour, resultMinute, resultSecond;
if (hour.startsWith("0")) {
resultHour = hour.substring(1);
} else {
resultHour = hour;
}
if (minute.startsWith("0")) {
resultMinute = minute.substring(1);
} else {
resultMinute = minute;
}
if (second.startsWith("0")) {
resultSecond = second.substring(1);
} else {
resultSecond = second;
}
switch (timeFormat) {
case TimeFormat.Jam:
return "$resultHour Jam ";
break;
case TimeFormat.JamMenit:
return "$resultHour Jam $resultMinute Menit";
break;
case TimeFormat.JamMenitDetik:
return "$resultHour Jam $resultMinute Menit $resultSecond Detik";
break;
case TimeFormat.Menit:
return "$resultMinute Menit";
break;
case TimeFormat.MenitDetik:
return "$resultMinute Menit $resultSecond Detik";
break;
case TimeFormat.Detik:
return "$resultSecond Detik";
break;
default:
return "$resultHour Jam $resultMinute Menit $resultSecond Detik";
}
}
Use
print(globalF.formatTimeTo("08:05:55", timeFormat: TimeFormat.JamMenitDetik));
//8 Jam 5 Menit 55 Detik

A convenient way is to use the intl package.
You can just define an extension on the Duration so you can easily access your required format across all screens. I would recommend this approach if you have to localize your app.
extension ExtensionOnDuration on Duration {
String get appFormat => DateFormat('h:mm', Platform.localeName)
.format(DateTime(1111, 1, 1, inHours, inMinutes % 60));
}

Related

How to include lastmonth last week in this months first week using ASP.Net MVC

I wrote a code that brings up Current Month Data and groups it by Week. This is great, but the issue here is that I want to also include Last month's Last weekdays in First Week for This month. The reason being the Current Month date is April 01st, 2021, but I am looking to group data for an entire week.
Here is the example
March Week 4 Starts on 29th March, which falls on Monday
Aprile Week 1 Starts on 01st April, which falls on Thursday.
So, If the Current Month First Week Number of Days is greater than Last Month Last Week Number of Days, how can I group the data in as April First Week which should be from March 29th TO April 04th.
The same shall continue for May, April Last Week has 5 days, and May First week has 2 days. Hence, the grouping should display data for Last Week Aprile and not in First Week May
Action Method
public ActionResult DisplayChart()
{
/*This Month Begin*/
DateTime now = DateTime.Now.AddDays(-3);
var startDate = new DateTime(now.Year, now.Month, 1);
var endDate = startDate.AddMonths(1).AddDays(-1);
/*This Month Ends*/
var result = db.Chats.Where(c => System.Data.Entity.DbFunctions.TruncateTime(c.MSTChatCreatedDateTime) >= startDate &&
System.Data.Entity.DbFunctions.TruncateTime(c.MSTChatCreatedDateTime) <= endDate).Select(x => new {x.MSTChatCreatedDateTime}).ToList().GroupBy(c => new
{
Year = c.MSTChatCreatedDateTime.ToCleanDateTime().Year,
Month = c.MSTChatCreatedDateTime.ToCleanDateTime().Month,
WeekofMonth = c.MSTChatCreatedDateTime.ToCleanDateTime().GetWeekOfMonth()
}).Select(c => new ReportVM
{
Title = string.Format("{0}/{1}/Week{2}", c.Key.Year, c.Key.Month, c.Key.WeekofMonth), //chart x Axis value.
ChatCountCreatdDate = c.Count() //chart y Axis value.
}).ToList();
//return the data to the view.
return View(result);
}
Thank you in advance
try this:
public class MyModel
{
public DateTime? Date { get; set; }
public string GroupBy
{
get
{
if (Date.HasValue)
{
DateTime nowDate = DateTime.UtcNow;
if (nowDate.ToString("dd/MM/yyyy") == Date.Value.ToString("dd/MM/yyyy"))
{
return "Today";
}
else if (nowDate.AddDays(-1).ToString("dd/MM/yyyy") == Date.Value.ToString("dd/MM/yyyy"))
{
return "Yesterday";
}
else if ((nowDate - Date.Value).TotalDays <= 7)
{
return Date.Value.DayOfWeek.ToString();
}
else if ((nowDate - Date.Value).TotalDays <= 14)
{
return "Last Week";
}
else if ((nowDate - Date.Value).TotalDays <= 21)
{
return "Two Weeks Ago";
}
else if ((nowDate - Date.Value).TotalDays <= 28)
{
return "Three Weeks Ago";
}
else if (nowDate.TotalMonths(Date.Value) == 1)
{
return "Last Month";
}
else
{
return "Older";
}
}
return string.Empty;
}
}
}

Formatting a Duration like HH:mm:ss

Is there a good way to format a Duration in something like hh:mm:ss, without having to deal with time zones?
I tried this:
DateTime durationDate = DateTime.fromMillisecondsSinceEpoch(0);
String duration = DateFormat('hh:mm:ss').format(durationDate);
But I always get 1 hour to much, in this case it would say 01:00:00
And When I do this:
Duration(milliseconds: 0).toString();
I get this: 0:00:00.000000
You can use Duration and implement this method:
String _printDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
Usage:
final now = Duration(seconds: 30);
print("${_printDuration(now)}");
You can start creating a format yourself, come on this one:
String sDuration = "${duration.inHours}:${duration.inMinutes.remainder(60)}:${(duration.inSeconds.remainder(60))}";
The shortest, most elegant and reliable way to get HH:mm:ss from a Duration is doing:
format(Duration d) => d.toString().split('.').first.padLeft(8, "0");
Example usage:
main() {
final d1 = Duration(hours: 17, minutes: 3);
final d2 = Duration(hours: 9, minutes: 2, seconds: 26);
final d3 = Duration(milliseconds: 0);
print(format(d1)); // 17:03:00
print(format(d2)); // 09:02:26
print(format(d3)); // 00:00:00
}
Just a quick implementation.
This will display the Duration in [DD]d:[HH]h:[mm]m:[ss]s format, and will ignore the leading element if it was 0. But seconds will always present.
For example:
1d:2h:3m:4s
2h:3m:4s
3m:4s
4s
0s
/// Returns a formatted string for the given Duration [d] to be DD:HH:mm:ss
/// and ignore if 0.
static String formatDuration(Duration d) {
var seconds = d.inSeconds;
final days = seconds~/Duration.secondsPerDay;
seconds -= days*Duration.secondsPerDay;
final hours = seconds~/Duration.secondsPerHour;
seconds -= hours*Duration.secondsPerHour;
final minutes = seconds~/Duration.secondsPerMinute;
seconds -= minutes*Duration.secondsPerMinute;
final List<String> tokens = [];
if (days != 0) {
tokens.add('${days}d');
}
if (tokens.isNotEmpty || hours != 0){
tokens.add('${hours}h');
}
if (tokens.isNotEmpty || minutes != 0) {
tokens.add('${minutes}m');
}
tokens.add('${seconds}s');
return tokens.join(':');
}
Based on #diegoveloper's answer, I made it an extension which is also extendible
extension DurationExtensions on Duration {
/// Converts the duration into a readable string
/// 05:15
String toHoursMinutes() {
String twoDigitMinutes = _toTwoDigits(this.inMinutes.remainder(60));
return "${_toTwoDigits(this.inHours)}:$twoDigitMinutes";
}
/// Converts the duration into a readable string
/// 05:15:35
String toHoursMinutesSeconds() {
String twoDigitMinutes = _toTwoDigits(this.inMinutes.remainder(60));
String twoDigitSeconds = _toTwoDigits(this.inSeconds.remainder(60));
return "${_toTwoDigits(this.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
String _toTwoDigits(int n) {
if (n >= 10) return "$n";
return "0$n";
}
}
Here's another version. It's all preference at this point, but I liked that it was dry and didn't need a function declaration (the wrapping function is obviously optional) though it is definately a bit function chaining heavy.
Compact
String formatTime(double time) {
Duration duration = Duration(milliseconds: time.round());
return [duration.inHours, duration.inMinutes, duration.inSeconds].map((seg) => seg.remainder(60).toString().padLeft(2, '0')).join(':');
}
Formatted version
String timeFormatter (double time) {
Duration duration = Duration(milliseconds: time.round());
return [duration.inHours, duration.inMinutes, duration.inSeconds]
.map((seg) => seg.remainder(60).toString().padLeft(2, '0'))
.join(':');
}
Define this:
extension on Duration {
String format() => '$this'.split('.')[0].padLeft(8, '0');
}
Usage:
String time = Duration(seconds: 3661).format(); // 01:01:01
Elaborating on other answers, here is an implementation that also formats days:
extension DurationFormatter on Duration {
/// Returns a day, hour, minute, second string representation of this `Duration`.
///
///
/// Returns a string with days, hours, minutes, and seconds in the
/// following format: `dd:HH:MM:SS`. For example,
///
/// var d = new Duration(days:19, hours:22, minutes:33);
/// d.dayHourMinuteSecondFormatted(); // "19:22:33:00"
String dayHourMinuteSecondFormatted() {
this.toString();
return [
this.inDays,
this.inHours.remainder(24),
this.inMinutes.remainder(60),
this.inSeconds.remainder(60)
].map((seg) {
return seg.toString().padLeft(2, '0');
}).join(':');
}
}
Unfortunately the intl package DateFormat class does not help: it marks the format of a Duration as not implemented:
formatDuration(DateTime reference) → String
NOT YET IMPLEMENTED. [...]
In my opinion the easiest way
String get refactoredDuration{
return Duration(seconds: duration).toString().split('.')[0];
}
You can use this:
print('${duration.inHours.toString().padLeft(2, '0')}:
${duration.inMinutes.remainder(60).toString().padLeft(2, '0')}:
${duration.inSeconds.remainder(60).toString().padLeft(2, '0')}');
I prefer thinking of Millisecond as its own unit, rather than as a subunit of something else. In that sense, it will have values of 0-999, so you're going to want to Pad three instead of two like I have seen with other answers. Here is an implementation:
String format(Duration o) {
var mil_s = (o.inMilliseconds % 1000).toString().padLeft(3, '0');
var sec_s = (o.inSeconds % 60).toString().padLeft(2, '0');
return o.inMinutes.toString() + ' m ' + sec_s + ' s ' + mil_s + ' ms';
}
https://api.dart.dev/dart-core/Duration-class.html
You can use this:
Text(RegExp(r'((^0*[1-9]\d*:)?\d{2}:\d{2})\.\d+$')
.firstMatch("$duration") ?.group(1) ?? '$duration'),
String myDuration(Duration duration) {
var date = duration.toString().split(":");
var hrs = date[0];
var mns = date[1];
var sds = date[2].split(".")[0];
return "$hrs:$mns:$sds";
}
Modified the first so when hours are in 00 it will not show.
extension VideoTimer on Duration {
String format() {
String twoDigits(int n) => n.toString().padLeft(2, '0');
final String twoDigitMinutes = twoDigits(inMinutes.remainder(60));
final String twoDigitSeconds = twoDigits(inSeconds.remainder(60));
final hour = twoDigits(inHours);
return "${hour == '00' ? '' : hour + ':'}$twoDigitMinutes:$twoDigitSeconds";
}
}
String _printDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "$twoDigitMinutes:$twoDigitSeconds";
}
Container( //duration of video
child: Text("Total Duration: " + _printDuration(_controller.value.duration).toString()+" Position: " + _printDuration(_controller.value.position).toString()),
),

iOS in-app purchase subscription get free trial period length from SKProduct

I am working on in-app purchases with subscriptions.
In swift, you can get price and price locale from the SKProduct like so:
weeklyProduct.price.doubleValue
weeklyProduct.priceLocale.currencySymbol
where weeklyProduct is a SKProduct.
Is it possible to get the free trial length? For example, I specified a two week free trial for the product. can I get this from the SKProduct?
I've solved it using DateComponentsFormatter, that saves you a lot of time localizing in different languages and handling plurals and whatnot.
This might seem like a lot of code, but I hope it will save me time in the future.
import Foundation
class PeriodFormatter {
static var componentFormatter: DateComponentsFormatter {
let formatter = DateComponentsFormatter()
formatter.maximumUnitCount = 1
formatter.unitsStyle = .full
formatter.zeroFormattingBehavior = .dropAll
return formatter
}
static func format(unit: NSCalendar.Unit, numberOfUnits: Int) -> String? {
var dateComponents = DateComponents()
dateComponents.calendar = Calendar.current
componentFormatter.allowedUnits = [unit]
switch unit {
case .day:
dateComponents.setValue(numberOfUnits, for: .day)
case .weekOfMonth:
dateComponents.setValue(numberOfUnits, for: .weekOfMonth)
case .month:
dateComponents.setValue(numberOfUnits, for: .month)
case .year:
dateComponents.setValue(numberOfUnits, for: .year)
default:
return nil
}
return componentFormatter.string(from: dateComponents)
}
}
It requires to convert the SKProduct period unit into a NSCalendarUnit
import StoreKit
#available(iOS 11.2, *)
extension SKProduct.PeriodUnit {
func toCalendarUnit() -> NSCalendar.Unit {
switch self {
case .day:
return .day
case .month:
return .month
case .week:
return .weekOfMonth
case .year:
return .year
#unknown default:
debugPrint("Unknown period unit")
}
return .day
}
}
And you can call it from a SubscriptionPeriod like this:
import StoreKit
#available(iOS 11.2, *)
extension SKProductSubscriptionPeriod {
func localizedPeriod() -> String? {
return PeriodFormatter.format(unit: unit.toCalendarUnit(), numberOfUnits: numberOfUnits)
}
}
Which you can in turn call from a SKProductDiscount like so. Please note I didn't implement the other PaymentModes for now.
import StoreKit
#available(iOS 11.2, *)
extension SKProductDiscount {
func localizedDiscount() -> String? {
switch paymentMode {
case PaymentMode.freeTrial:
return "Free trial for \(subscriptionPeriod.localizedPeriod() ?? "a period")"
default:
return nil
}
}
}
You can get it, but as mentioned above it works only starting from iOS 11.2, for other versions you'll have to get it from your server via API.
Here is an example code that I've used:
if #available(iOS 11.2, *) {
if let period = prod.introductoryPrice?.subscriptionPeriod {
print("Start your \(period.numberOfUnits) \(unitName(unitRawValue: period.unit.rawValue)) free trial")
}
} else {
// Fallback on earlier versions
// Get it from your server via API
}
func unitName(unitRawValue:UInt) -> String {
switch unitRawValue {
case 0: return "days"
case 1: return "weeks"
case 2: return "months"
case 3: return "years"
default: return ""
}
}
Using Eslam's answer as inspiration I created an extension to SKProduct.PeriodUnit
extension SKProduct.PeriodUnit {
func description(capitalizeFirstLetter: Bool = false, numberOfUnits: Int? = nil) -> String {
let period:String = {
switch self {
case .day: return "day"
case .week: return "week"
case .month: return "month"
case .year: return "year"
}
}()
var numUnits = ""
var plural = ""
if let numberOfUnits = numberOfUnits {
numUnits = "\(numberOfUnits) " // Add space for formatting
plural = numberOfUnits > 1 ? "s" : ""
}
return "\(numUnits)\(capitalizeFirstLetter ? period.capitalized : period)\(plural)"
}
}
To use:
if #available(iOS 11.2, *),
let period = prod?.introductoryPrice?.subscriptionPeriod
{
let desc = period.unit.description(capitalizeFirstLetter: true, numberOfUnits: period.numberOfUnits)
} else {
// Fallback
}
This will create a nicely formatted string (e.g. 1 day, 1 Week, 2 months, 2 Years)
Nice one #scott Wood. I would make it a property of SKProduct.PeriodUnit instead of a function. That would keep the behaviour more consistent with enums:
#available(iOS 11.2, *)
extension SKProduct.PeriodUnit {
var description: String {
switch self {
case .day: return "day"
case .week: return "week"
case .month: return "month"
case .year: return "year"
// support for future values
default:
return "N/A"
}
}
func pluralisedDescription(length: Int) -> String {
let lengthAndDescription = length.description + " " + self.description
let plural = length > 1 ? lengthAndDescription + "s" : lengthAndDescription
return plural
}
}
And then a function to return the plural, based on the description property.
And yes, as someone else pointed out, you should localise the plurals if your app is available in other languages.
Trial length is not included in the SKProduct information and will have to be hardcoded into the app or stored on your server. The only available option for deriving this type of information (currently) is from the receipt itself.
Starting from iOS 11.2 you can get info about trials using introductoryPrice property of SKProduct.
It contains instance of SKProductDiscount class, which describes all discount periods including free trials.
Swift 5
Using Eslam's and Scott's answers as inspiration:
import StoreKit
extension SKProduct {
func priceString() -> String {
let period:String = {
switch self.subscriptionPeriod?.unit {
case .day: return "day"
case .week: return "week"
case .month: return "month"
case .year: return "year"
case .none: return ""
case .some(_): return ""
}
}()
let price = self.localizedPrice!
let numUnits = self.subscriptionPeriod?.numberOfUnits ?? 0
let plural = numUnits > 1 ? "s" : ""
return String(format: "%# for %d %#%#", arguments: [price, numUnits, period, plural])
}
}
To use:
let price = product.priceString()
print(price)
Result:
THB 89.00 for 7 days
THB 149.00 for 1 month
+ (NSString*)localizedTitleForSKPeriod:(SKProductSubscriptionPeriod*)period{
NSDateComponents *comps = [NSDateComponents new];
NSDateComponentsFormatter *fmt = [NSDateComponentsFormatter new];
switch (period.unit) {
case SKProductPeriodUnitDay:{
fmt.allowedUnits = NSCalendarUnitDay;
comps.day = period.numberOfUnits;
}break;
case SKProductPeriodUnitWeek:{
fmt.allowedUnits = NSCalendarUnitWeekOfMonth;
comps.weekOfMonth = period.numberOfUnits;
}break;
case SKProductPeriodUnitMonth:{
fmt.allowedUnits = NSCalendarUnitMonth;
comps.month = period.numberOfUnits;
}break;
case SKProductPeriodUnitYear: {
fmt.allowedUnits = NSCalendarUnitYear;
comps.year = period.numberOfUnits;
}break;
}
// 1 Day, 1 Week, 2 Weeks, 1 Month, 2 Months, 3 Months, 6 Months, 1 Year
fmt.unitsStyle = NSDateComponentsFormatterUnitsStyleFull;
// One Day, One Week, Two Weeks, etc
//fmt.unitsStyle = NSDateComponentsFormatterUnitsStyleSpellOut;
NSString *s = [[fmt stringFromDateComponents:comps] capitalizedString];
return s;
}
OBJECTIVE C
#import "SKProduct+SKProduct.h"
-(NSString*_Nullable)localizedTrialDuraion{
if (#available(iOS 11.2, *)) {
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
[formatter setUnitsStyle:NSDateComponentsFormatterUnitsStyleFull]; //e.g 1 month
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropAll;
NSDateComponents * dateComponents = [[NSDateComponents alloc]init];
[dateComponents setCalendar:[NSCalendar currentCalendar]];
switch (self.introductoryPrice.subscriptionPeriod.unit) {
case SKProductPeriodUnitDay:{
formatter.allowedUnits = NSCalendarUnitDay;
[dateComponents setDay:self.introductoryPrice.subscriptionPeriod.numberOfUnits];
break;
}
case SKProductPeriodUnitWeek:{
formatter.allowedUnits = NSCalendarUnitWeekOfMonth;
[dateComponents setWeekOfMonth:self.introductoryPrice.subscriptionPeriod.numberOfUnits];
break;
}
case SKProductPeriodUnitMonth:{
formatter.allowedUnits = NSCalendarUnitMonth;
[dateComponents setMonth:self.introductoryPrice.subscriptionPeriod.numberOfUnits];
break;
}
case SKProductPeriodUnitYear:{
formatter.allowedUnits = NSCalendarUnitYear;
[dateComponents setYear:self.introductoryPrice.subscriptionPeriod.numberOfUnits];
break;
}
default:{
return nil;
break;
}
break;
}
[dateComponents setValue:self.introductoryPrice.subscriptionPeriod.numberOfUnits forComponent:formatter.allowedUnits];
return [formatter stringFromDateComponents:dateComponents];
} else {
// Fallback on earlier versions
}
return nil;
}
Here is more compact and short in use version for swift 5, extending SKProductSubscriptionPeriod
Usage:
print("\(period.localizedDescription) free trial")
//Printed example "1 week free trial"
Implementation:
extension SKProductSubscriptionPeriod {
public var localizedDescription: String {
let period:String = {
switch self.unit {
case .day: return "day"
case .week: return "week"
case .month: return "month"
case .year: return "year"
#unknown default:
return "unknown period"
}
}()
let plural = numberOfUnits > 1 ? "s" : ""
return "\(numberOfUnits) \(period)\(plural)"
}
}
If you use SwiftyStoreKit, localizedSubscriptionPeriod is the easiest way
import SwiftyStoreKit
product.introductoryPrice?.localizedSubscriptionPeriod // "1 week"
This is the implementation:
https://github.com/bizz84/SwiftyStoreKit/blob/master/Sources/SwiftyStoreKit/SKProductDiscount+LocalizedPrice.swift

Modifiy child constantly by using the UploadDate

I am currently building an Instagram clone.
I am quit new so please forgive me if this question is answered easily.
I just want to have a specific score attached to each post.
I already managed to give each new post a score 0f 0 to start with and each time its liked it increases by 100, disliked it decreases by 100.
for every comment it grows by 50 points.
Because I want to order them smartly and want it to show different posts at the top over time I wanted to include a third variable which influences the score.
I want it to decrease the score by -10 each hour since its been uploaded.
The increase and decrease is done in my function incrementLikes() /incrementComments() .
I know that I can't modify the value of score for the time since its uploaded there, but I don't know where else.
My date extension (prob where I can do it?)
extension Date {
func timeAgoDisplay() -> String {
let secondsAgo = Int(Date().timeIntervalSince(self))
let minute = 60
let hour = 60 * minute
let day = hour * 24
let week = day * 7
let month = week * 4
let quotient : Int
let unit: String
if secondsAgo < minute {
quotient = secondsAgo
unit = "Sekunde"
} else if secondsAgo < hour {
quotient = secondsAgo / minute
unit = "Minute"
} else if secondsAgo < day {
quotient = secondsAgo / hour
unit = "Stunde"
} else if secondsAgo < week {
quotient = secondsAgo / day
unit = "Tage"
} else if secondsAgo < month {
quotient = secondsAgo / week
unit = "Woche"
} else {
quotient = secondsAgo / month
unit = "Monat"
}
return "Vor \(quotient) \(unit)\(quotient == 1 ? "" : "n")"
}
}
my function in homeTableViewCell where I set the date
func updateView() {
captionLabel.userHandleLinkTapHandler = { label,string, range in
let mention = String(string.characters.dropFirst())
API.User.observeUserByUsername(username: mention.lowercased(), completion: { (user) in
self.delegate?.goToProfileUserViewController(userId: user.id!)
})
}
guard let count = post?.commentCount else {return}
if count == 0 {
commentButton.setTitle("Schreibe den ersten Kommentar", for: UIControlState.normal)
}else if count == 1 {
commentButton.setTitle("Sieh dir den ersten Kommentar an", for: UIControlState.normal)
} else {
commentButton.setTitle("Alle \(count) Kommentare ansehen", for: UIControlState.normal)
}
let timeAgoDisplay = post?.creationDate?.timeAgoDisplay()
timeLabel.text = timeAgoDisplay
}
thanks for your help :)
The idea of updating the score every hour using a time is based on the idea that the app is constantly running, which seems flawed.
You could instead have something like
var score: Int {
return likes*100 - dislikes*100 + comments*50 - hoursSinceUpload()*10
}
where hoursSinceUpload is computed by something like (see Getting the difference between two NSDates in (months/days/hours/minutes/seconds) for reference)
func hoursSinceUpload() -> Int {
return Calendar.current.dateComponents([.hour], from: uploadDate, to: Date()).hour
}

Highchart xAxis labels formatter not displaying returned value

I've been fighting this problem for most of the day now, so I figure I'd ask here...
I'm creating a plot using highcharts, and I want to use a datetime xAxis. The label I wish to show on this axis is a calculated value, relative to a set of specific dates. So I use a labels.formatter function which have access to the previous and the last dates, and relative to these dates I do some logics.
The logic is that if this.value (from within the formatter) is before the last one, the axis should show months since previous ones, if this.value == last it should show 0 and if this.value > last it should show months since last.
I have some helper functions that are called in my code, they have been used in many occasions and work as they should.
Below is the implementation of my label formatter for the xAxis.
gVars.reportAddedResistance.MonthSinceUsed = new Array();
this.highchart.options.xAxis.labels.formatter = function() {
var mbDec;
var mod;
var result;
var returnValue = null;
var isSet;
var previous = new Date(self.data.plotConf.previousDrydockDate);
var last = new Date(self.data.plotConf.lastDrydockDate);
var val = new Date(this.value);
if(val.getTime() < last.getTime()) {
// BEFORE LAST DRYDOCK
mbDec = Utils.monthsBetweenDecimal(previous, val);
mod = mbDec % 1;
if(mod <= (1 / 30.4375)) {
result = Math.round(mbDec);
isSet = gVars.reportAddedResistance.MonthSinceUsed.indexOf(result);
if(isSet == -1) {
gVars.reportAddedResistance.MonthSinceUsed.push(result);
//console.log('',"LESS Returning "+result+" Used: "+gVars.reportAddedResistance.MonthSinceUsed);
returnValue = result;
}
}
}
else if(val.getTime() == last.getTime()){
// AT LAST DRYDOCK
var result = 0;
isSet = gVars.reportAddedResistance.MonthSinceUsed.indexOf(result);
if(isSet == -1) {
gVars.reportAddedResistance.MonthSinceUsed.push(result);
//console.log('',"EVEN Returning "+result+" Used: "+gVars.reportAddedResistance.MonthSinceUsed);
returnValue = result;
}
}
else if(val.getTime() > last.getTime()){
// AFTER LAST DRYDOCK
mbDec = Utils.monthsBetweenDecimal(last, val);
mod = mbDec % 1;
if(mod <= (1 / 30.4375)) {
result = Math.round(mbDec);
isSet = gVars.reportAddedResistance.MonthSinceUsed.indexOf(result);
if(isSet == -1) {
gVars.reportAddedResistance.MonthSinceUsed.push(result);
//console.log('',"MORE Returning "+result+" Used: "+gVars.reportAddedResistance.MonthSinceUsed);
returnValue = result;
}
}
}
return returnValue;
};
The value of previous is (from console.log):
Date {Tue Jun 15 2010 02:00:00 GMT+0200 (Romance Daylight Time)}
The value of last is (from console.log):
Date {Sat Jun 15 2013 02:00:00 GMT+0200 (Romance Daylight Time)}
If I enable the console.log output I get this output, which to me indicates that the logics and date comparisons is working as expected:
LESS Returning 31 Used: 31
LESS Returning 32 Used: 31,32
LESS Returning 33 Used: 31,32,33
LESS Returning 34 Used: 31,32,33,34
LESS Returning 35 Used: 31,32,33,34,35
EVEN Returning 0 Used: 31,32,33,34,35,0
MORE Returning 1 Used: 31,32,33,34,35,0,1
MORE Returning 2 Used: 31,32,33,34,35,0,1,2
MORE Returning 3 Used: 31,32,33,34,35,0,1,2,3
MORE Returning 4 Used: 31,32,33,34,35,0,1,2,3,4
MORE Returning 5 Used: 31,32,33,34,35,0,1,2,3,4,5
MORE Returning 6 Used: 31,32,33,34,35,0,1,2,3,4,5,6
MORE Returning 7 Used: 31,32,33,34,35,0,1,2,3,4,5,6,7
MORE Returning 8 Used: 31,32,33,34,35,0,1,2,3,4,5,6,7,8
My problem is, that the returned values are not displayed on my plot. If I change the formatter function to just return this.value it displays them all, without any problems, but for some reason I cannot identify the return values (as seen in the above console.log output) is not shown.
My xAxis is configured like this:
xAxis: {
type : 'datetime',
dateTimeLabelFormats: {
day: '%Y-%m-%d',
week: '%Y-%m-%d',
month: '%Y-%m-%d',
year: '%Y-%m'
},
startOnTick : false,
tickInterval : 24 * 3600 * 1000 * 1, // 1 day
title : {
text : 'Months relative to drydockings',
style : {
fontSize : '9pt',
fontFamily : 'Arial'
}
},
labels : {
maxStaggerLines : 1,
style : {
fontSize : '7pt',
fontFamily : 'Arial'
}
}
},
I'm stuck - PLEASE HELP!!! :-)
EDIT: I'm using Highcharts JS v3.0.7 (2013-10-24)
The solution to my problem was to add this to the formatter:
if(this.isFirst) {
gVars.noOfSeriesCalled++;
}
if(gVars.noOfSeriesCalled == this.axis.series.length) {
// The stuff thats posted above
}
else {
return null;
}
I think its an error in the library that I have to use a global variable to keep track of how many iterations I've been through.
The correct implementation, as seen from my perspective, would be that the formatting function were called once for each tick in the xAxis, regardless of how many series are added to the plot.

Resources