Convert HH:MM:SS to seconds in xcode - ios

Hi I have the code to separate hour,min,sec
Now i have to convert it in to seconds.and nsnumber
NSRange range = [string rangeOfString:#":"];
NSString *hour = [string substringToIndex:range.location];
NSLog(#"time %#",hour);
NSRange range1= NSMakeRange(2,2);
NSString *min = [string substringWithRange:range1];
NSLog(#"time %#",min);
NSRange range2 = NSMakeRange(5,2);
NSString *sec = [string substringWithRange:range2];
NSLog(#"time %#",sec);

If you want to find out how many seconds the hours, minutes and seconds total, you can do something like this:
- (NSNumber *)secondsForTimeString:(NSString *)string {
NSArray *components = [string componentsSeparatedByString:#":"];
NSInteger hours = [[components objectAtIndex:0] integerValue];
NSInteger minutes = [[components objectAtIndex:1] integerValue];
NSInteger seconds = [[components objectAtIndex:2] integerValue];
return [NSNumber numberWithInteger:(hours * 60 * 60) + (minutes * 60) + seconds];
}

Just an alternative if you have to handle both "HH:mm:ss" and "mm:ss"
extension String {
/**
Converts a string of format HH:mm:ss into seconds
### Expected string format ###
````
HH:mm:ss or mm:ss
````
### Usage ###
````
let string = "1:10:02"
let seconds = string.inSeconds // Output: 4202
````
- Returns: Seconds in Int or if conversion is impossible, 0
*/
var inSeconds : Int {
var total = 0
let secondRatio = [1, 60, 3600] // ss:mm:HH
for (i, item) in self.components(separatedBy: ":").reversed().enumerated() {
if i >= secondRatio.count { break }
total = total + (Int(item) ?? 0) * secondRatio[i]
}
return total
}
}

Swift 4 - improved from #Beslan Tularov's answer.
extension String{
var integer: Int {
return Int(self) ?? 0
}
var secondFromString : Int{
var components: Array = self.components(separatedBy: ":")
let hours = components[0].integer
let minutes = components[1].integer
let seconds = components[2].integer
return Int((hours * 60 * 60) + (minutes * 60) + seconds)
}
}
Usage
let xyz = "00:44:22".secondFromString
//result : 2662

You can also try like this:
extension String{
//format hh:mm:ss or hh:mm or HH:mm
var secondFromString : Int{
var n = 3600
return self.components(separatedBy: ":").reduce(0) {
defer { n /= 60 }
return $0 + (Int($1) ?? 0) * n
}
}
}
var result = "00:44:22".secondFromString //2662
result = "00:44".secondFromString //2640
result = "01:44".secondFromString //6240
result = "999:10".secondFromString //3597000
result = "02:44".secondFromString //9840
result = "00:01".secondFromString //60
result = "00:01:01".secondFromString //61
result = "01:01:01".secondFromString //3661
result = "12".secondFromString //43200
result = "abcd".secondFromString //0

From what you've,
double totalSeconds = [hour doubleValue] * 60 * 60 + [min doubleValue] * 60 + [sec doubleValue];
NSNumber * seconds = [NSNumber numberWithDouble:totalSeconds];

The following is a String extension for converting a time string (HH:mm:ss) to seconds
extension String {
func secondsFromString (string: String) -> Int {
var components: Array = string.componentsSeparatedByString(":")
var hours = components[0].toInt()!
var minutes = components[1].toInt()!
var seconds = components[2].toInt()!
return Int((hours * 60 * 60) + (minutes * 60) + seconds)
}
}
how to use
var exampleString = String().secondsFromString("00:30:00")

You can use the following extension to do that (Swift 3):
extension String {
func numberOfSeconds() -> Int {
var components: Array = self.components(separatedBy: ":")
let hours = Int(components[0]) ?? 0
let minutes = Int(components[1]) ?? 0
let seconds = Int(components[2]) ?? 0
return (hours * 3600) + (minutes * 60) + seconds
}
}
And for example, use it like:
let seconds = "01:30:10".numberOfSeconds()
print("%# seconds", seconds)
Which will print:
3790 seconds

Related

swift3 Date to Data, Data to Date convert

I am working on changing the code created in objective c to swift3.
I want to change the code below to the swift3 code created with objective c.
Objective c NSDate to NSData code :
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:NSDayCalendarUnit |NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:[NSDate date]];
NSInteger year = components.year;
NSMutableData *yearData = [[NSMutableData alloc] initWithBytes:&year length:sizeof(year)];
int year1 = *(int *)[[yearData subdataWithRange:NSMakeRange(0, 1)] bytes];
int year2 = *(int *)[[yearData subdataWithRange:NSMakeRange(1, 1)] bytes];
int month = components.month;
int day = components.day;
int hour = components.hour;
int min = components.minute;
int second = components.second;
char bytes[7];
bytes[0] = year1;
bytes[1] = year2;
bytes[2] = month;
bytes[3] = day;
bytes[4] = hour;
bytes[5] = min;
bytes[6] = second;
NSData *data = [[NSData alloc] initWithBytes:&bytes length:sizeof(bytes)];
Objective c NSData to NSDate code :
NSData *date = [[NSData alloc] initWithData:characteristic.value];
int year = *(int *)[[date subdataWithRange:NSMakeRange(0, 2)] bytes];
int month = *(int *)[[date subdataWithRange:NSMakeRange(2, 1)] bytes];
int day = *(int *)[[date subdataWithRange:NSMakeRange(3, 1)] bytes];
int hour = *(int *)[[date subdataWithRange:NSMakeRange(4, 1)] bytes];
int minutes = *(int *)[[date subdataWithRange:NSMakeRange(5, 1)] bytes];
int seconds = *(int *)[[date subdataWithRange:NSMakeRange(6, 1)] bytes];
NSLog(#"year %d month %d day %d hour %d minutes %d second %d", year, month, day, hour, minutes, seconds); //year 2017 month 7 day 13 hour 16 minutes 8 second 2
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setYear:year];
[components setMonth:month];
[components setDay:day];
[components setHour:hour];
[components setMinute:minutes];
[components setSecond:seconds];
NSCalendar *calendar = [NSCalendar currentCalendar];
self.time = [calendar dateFromComponents:components];
Swift Date to Data code :
let cal = Calendar(identifier: .gregorian)
var comp = cal.dateComponents([.day,.month,.year,.hour,.minute,.second], from: Date())
var year = comp.year
let yearData:Data = Data(bytes: &year, count: MemoryLayout.size(ofValue: year))
let year1:Data = yearData.subdata(in: 0..<1)
let year2:Data = yearData.subdata(in: 1..<2)
let settingArray = [UInt8]([
UInt8(year1[0])
, UInt8(year2[0])
, UInt8(comp.month!)
, UInt8(comp.day!)
, UInt8(comp.hour!)
, UInt8(comp.minute!)
, UInt8(comp.second!)
])
let settingData:Data = Data(bytes: settingArray, count: MemoryLayout.size(ofValue: settingArray))
Swift Data to Date code :
var yearVal:UInt8 = 0
let year = characteristic.value?.subdata(in: 0..<2)
year?.copyBytes(to: &yearVal, count: MemoryLayout.size(ofValue: year))
var month = characteristic.value?.subdata(in: 2..<3)
var day = characteristic.value?.subdata(in: 3..<4)
var hour = characteristic.value?.subdata(in: 4..<5)
var minutes = characteristic.value?.subdata(in: 5..<6)
var seconds = characteristic.value?.subdata(in: 6..<7)
print("year = \(yearVal), month = \(Int((month?[0])!)), day = \(Int((day?[0])!)), hour = \(Int((hour?[0])!)), minutes = \(Int((minutes?[0])!)), seconds = \(Int((seconds?[0])!))") // year = 225, month = 7, day = 13, hour = 15, minutes = 56, seconds = 56
When I modify the let year = characteristic.value?.subdata(in: 0..<2) part, the conversion value should be 2017. However, only 225 values are output. I do not know how to solve this part.
Please help me.
You are very lucky your Objective-C code works as you are reading unassigned memory and ignoring endian issues.
Consider the line:
int month = *(int *)[[date subdataWithRange:NSMakeRange(2, 1)] bytes];
Here you are taking a pointer to a single byte, casting it to a pointer to 4 bytes (the size on an int), and then reading 4 bytes and storing them in month. By luck the extra three bytes you read happen to be zero.
Then there is the endian issue, different cpu architectures store multi-byte values in different orders in memory. A little-endian architecture stores the least significant byte first, a big-endian one the most significant.
E.g. the 4-byte integer 0xDEADBEEF is stored as the byte sequence EF, BE, AD, DE on a little-endian machine and as DE, AD, BE, EF on a big-endian one. What this means in terms of your month value above is if the byte is 06 then you might get back the integer 0x06000000 when you read those 4 bytes (and only if those extra bytes are zeroes).
For the month case you could load the byte and then convert to an integer:
int month = (int *)(*(Byte *)[[date subdataWithRange:NSMakeRange(2, 1)] bytes]);
When converting the year to two bytes you go through the long winded process:
NSMutableData *yearData = [[NSMutableData alloc] initWithBytes:&year length:sizeof(year)];
int year1 = *(int *)[[yearData subdataWithRange:NSMakeRange(0, 1)] bytes];
int year2 = *(int *)[[yearData subdataWithRange:NSMakeRange(1, 1)] bytes];
This converts an integer to an NSData, makes to more NSData values containing 1 byte each, and then loads 4 bytes for each - the same issue as above, but in this case as you will only be storing 1 byte in your bytes array it doesn't matter if the extra bytes are garbage.
The process is convoluted, you would be better off sticking with integer operations to obtain the two values. You can obtain the individual bytes using division and remainder operations, or bit-wise shift and mask operations.
E.g. using decimal first to demonstrate:
int year = 2017;
int firstDigit = year % 10; // the remainder of year / 10 => 7
int secondDigit = (year / 10) % 10; // 1
int thirdDigit = (year / 100) % 10; // 0
int fourthDigit = (year / 1000) % 10; // 2
To extract the bytes just change the divisor:
int year = 2017; // = 0x7E1
int loByte = year % 256; // = 0xE1
int hiByte = (year / 256) % 256; // = 0x7
Finally you can use bit-wise shift and masking:
int year = 2017; // = 0x7E1
int loByte = year & 0xFF; // = 0xE1
int hiByte = (year >> 8) & 0xFF; // = 0x7
Using bit-wise operations makes the byte splitting more obvious, but divide and remainder achieve the same result.
What does all this mean in terms of your Objective-C code? Well the second of your two methods can be written:
+ (NSDate *) dataToDate:(NSData *)data
{
NSDateComponents *components = [[NSDateComponents alloc] init];
const Byte *bytes = data.bytes;
components.year = (NSInteger)bytes[0] | ((NSInteger)bytes[1] << 8); // reassemble 2-byte value
components.month = (NSInteger)bytes[2];
components.day = (NSInteger)bytes[3];
components.hour = (NSInteger)bytes[4];
components.minute = (NSInteger)bytes[5];
components.second = (NSInteger)bytes[6];
NSCalendar *calendar = [NSCalendar currentCalendar];
return[calendar dateFromComponents:components];
}
This is a lot less complex, doesn't read random memory, and is easier to convert to Swift.
Following the same approach here is your first method in Swift:
func toData(_ date : Date) -> Data
{
let cal = Calendar(identifier: .gregorian)
let comp = cal.dateComponents([.day,.month,.year,.hour,.minute,.second], from: date)
let year = comp.year!
let yearLo = UInt8(year & 0xFF) // mask to avoid overflow error on conversion to UInt8
let yearHi = UInt8(year >> 8)
let settingArray = [UInt8]([
yearLo
, yearHi
, UInt8(comp.month!)
, UInt8(comp.day!)
, UInt8(comp.hour!)
, UInt8(comp.minute!)
, UInt8(comp.second!)
])
return Data(bytes: settingArray)
}
Finally, you can index the Data type in Swift lust like an array, so the above Objective-C line:
components.month = (NSInteger)bytes[2];
where bytes came from calling NSData's bytes can be written directly in Swift as:
components.month = Int(data[2])
where data is the Data value.
The above approach doesn't answer the issue you actually had, because it avoids messing with splitting data values into bits and trying to extra values from them - just index the byte and convert with a cast.
The rest of the code you need is left as an excercise!
HTH
you are fetching year value as UInt8 which only have range of 0-255 so use UInt32
var yearVal: UInt32 = 0
(year as! NSData).getBytes(&yearVal, length: MemoryLayout.size(ofValue: year))

IBAN Validator Swift

I am writing an algorithm to validate IBAN (International Bank Account Number) in Swift 3 and not able to figure one of the validation.
Example IBAN - BE68539007547034
Here are the rules to validate -
Input number should be of length 16.
First 2 characters are country code (not numeric).
Last 14 are numeric.
Last 2 characters are the modulo 97 result of the previous 12 numeric characters.
While #1 - #3 are clear I need clarity on #4. If anyone have done this before and know about it then please let me know.
The validation algorithm is rather simple if you follow the algorithm on wikipedia:
extension String {
private func mod97() -> Int {
let symbols: [Character] = Array(self)
let swapped = symbols.dropFirst(4) + symbols.prefix(4)
let mod: Int = swapped.reduce(0) { (previousMod, char) in
let value = Int(String(char), radix: 36)! // "0" => 0, "A" => 10, "Z" => 35
let factor = value < 10 ? 10 : 100
return (factor * previousMod + value) % 97
}
return mod
}
func passesMod97Check() -> Bool {
guard self.characters.count >= 4 else {
return false
}
let uppercase = self.uppercased()
guard uppercase.range(of: "^[0-9A-Z]*$", options: .regularExpression) != nil else {
return false
}
return (uppercase.mod97() == 1)
}
}
Usage:
let iban = "XX0000000..."
let valid = iban.passesMod97Check()
If you want to validate the format for a specific country, just modify the regular expression, e.g.
"^[A-Z]{2}[0-9]{14}$"
or directly
"^BE\\d{14}$"
From Wikipedia
let IBAN = "GB82WEST12345698765432" // uppercase, no whitespace !!!!
var a = IBAN.utf8.map{ $0 }
while a.count < 4 {
a.append(0)
}
let b = a[4..<a.count] + a[0..<4]
let c = b.reduce(0) { (r, u) -> Int in
let i = Int(u)
return i > 64 ? (100 * r + i - 55) % 97: (10 * r + i - 48) % 97
}
print( "IBAN \(IBAN) is", c == 1 ? "valid": "invalid")
prints
IBAN GB82WEST12345698765432 is valid
With IBAN from your question it prints
IBAN BE68539007547034 is valid
I finded a great solution that work for me in Objective-C
https://gist.github.com/0xc010d/5301790 you can rewrite for Swift or use bridging header. Objective-C implementation of mod97 IBAN checking algorithm
#import <Foundation/Foundation.h>
#interface NSString (Mod97Check)
- (BOOL)passesMod97Check; // Returns result of mod 97 checking algorithm. Might be used to check IBAN.
// Expects string to contain digits and/or upper-/lowercase letters; space and all the rest symbols are not acceptable.
#end
#import "NSString+Mod97Check.h"
#implementation NSString (Mod97Check)
- (BOOL)passesMod97Check {
NSString *string = [self uppercaseString];
NSInteger mod = 0, length = [self length];
for (NSInteger index = 4; index < length + 4; index ++) {
unichar character = [string characterAtIndex:index % length];
if (character >= '0' && character <= '9') {
mod = (10 * mod + (character - '0')) % 97; // '0'=>0, '1'=>1, ..., '9'=>9
}
else if (character >= 'A' && character <= 'Z') {
mod = (100 * mod + (character - 'A' + 10)) % 97; // 'A'=>10, 'B'=>11, ..., 'Z'=>35
}
else {
return NO;
}
}
return (mod == 1);
}
#end
-(BOOL)isValidIBAN {
NSString *iban = self;
static NSString* const LettersAndDecimals = #"ABCDEFGHIJKLKMNOPQRSTUVWXYZ0123456789";
iban = [[iban stringByReplacingOccurrencesOfString:#" " withString:#""] uppercaseString];
NSCharacterSet *invalidChars = [[NSCharacterSet characterSetWithCharactersInString:LettersAndDecimals] invertedSet];
if ([iban rangeOfCharacterFromSet:invalidChars].location != NSNotFound)
{
return NO;
}
int checkDigit = [iban substringWithRange:NSMakeRange(2, 2)].intValue;
iban = [NSString stringWithFormat:#"%#%#",[iban substringWithRange:NSMakeRange(4, iban.length - 4)], [iban substringWithRange:NSMakeRange(0, 4)]] ;
for (int i = 0; i < iban.length; i++) {
unichar c = [iban characterAtIndex:i];
if (c >= 'A' && c <= 'Z') {
iban = [NSString stringWithFormat:#"%#%d%#", [iban substringWithRange:NSMakeRange(0, i)], (c - 'A' + 10),[iban substringWithRange:NSMakeRange(i+1, iban.length - i - 1)]];
}
}
iban = [[iban substringWithRange:NSMakeRange(0, iban.length - 2)] stringByAppendingString:#"00"];
while(true)
{
int iMin = (int)MIN(iban.length, 9);
NSString* strPart = [iban substringWithRange:NSMakeRange(0, iMin)];
int decnumber = strPart.intValue;
if(decnumber < 97 || iban.length < 3)
break;
int del = decnumber % 97;
iban = [NSString stringWithFormat:#"%d%#", del, [iban substringFromIndex:iMin]];
}
int check = 98 - iban.intValue;
return checkDigit == check;
}
Here you go :
func isValidIBAN(text:String) -> Bool {
let ibanRegEx = "[a-zA-Z]{2}+[0-9]{2}+[a-zA-Z0-9]{4}+[0-9]{7}([a-zA-Z0-9]?){0,16}"
let ibanTest = NSPredicate(format:"SELF MATCHES %#", ibanRegEx)
return ibanTest.evaluate(with: text)
}
It's clean, and it works.

Confusion about NSTimeZone.secondsFromGMT

I am developing an app that has a feature to enter dark/night mode during night hours automatically. The app asks for the user location and determines the sunrise/sunset hour (in Universal Time) using this algorithm.
The only step that is not clear is to convert from UT to local time, since this is not explained in the algorithm. Say I get a sunrise time of 8.5 (8:30 in the morning UT). How could I convert it to user's local time to check if it's day or night? Or equivalently, how could I convert user's local time to UT in order to be able to compare them?
So far I've tried to use NSCalendar to get the NSDateComponents of the current date (NSDate()). One of these components is a NSTimeZone? from which I can get the secondsFromGMT. Something like this:
let dateComponents = NSCalendar.currentCalendar().components([.TimeZone], fromDate: NSDate())
let localOffset = Double(dateComponents.timeZone?.secondsFromGMT ?? 0)/3600
where localOffset should be the time difference (in hours) from UT (i.e. GMT if I am right) to local time, defaulting to 0 if dateComponents.timeZone == nil (I don't know under which situations this could happen). The problem is that I get the same localOffset for now than for 6 months in the future (when the daylight saving time will be different than it is now at my location, Spain). Does this mean that I need to use the properties daylightSavingTime and/or daylightSavingTimeOffset together with secondsFromGMT? Doesn't secondsFromGMT itself account for this?
Things get even more confusing to me when I read the results from the algorithm. The sun setting hour (in local time) is exactly the one given by Google, but the sun rising hour is one hour ahead of what Google says (for my location and date). I share with you the whole Swift implementation of the algorithm hoping that it can help someone spot what's that I'm doing wrong.
import Foundation
import CoreLocation
enum SunriseSunsetZenith: Double {
case Official = 90.83
case Civil = 96
case Nautical = 102
case Astronomical = 108
}
func sunriseSunsetHoursForLocation(coordinate: CLLocationCoordinate2D, atDate date: NSDate = NSDate(), zenith: SunriseSunsetZenith = .Civil) -> (sunrise: Double, sunset: Double) {
// Initial values (will be changed later)
var sunriseTime = 7.5
var sunsetTime = 19.5
// Get the longitude and latitude
let latitude = coordinate.latitude
let longitude = coordinate.longitude
// Get the day, month, year and local offset
let dateComponents = NSCalendar.currentCalendar().components([.Day, .Month, .Year, .TimeZone], fromDate: date)
let day = Double(dateComponents.day)
let month = Double(dateComponents.month)
let year = Double(dateComponents.year)
let localOffset = Double(dateComponents.timeZone?.daylightSavingTimeOffset ?? 0)/3600
// Calculate the day of the year
let N1 = floor(275*month/9)
let N2 = floor((month + 9)/12)
let N3 = 1 + floor((year - 4*floor(year/4) + 2)/3)
let dayOfYear = N1 - N2*N3 + day - 30
for i in 0...1 {
// Convert the longitude to hour value and calculate an approximate time
let longitudeHour = longitude/15
let t = dayOfYear + ((i == 0 ? 6.0 : 18.0) - longitudeHour)/24
// Calculate the Sun's mean anomaly
let M = 0.9856*t - 3.289
// Calculate the Sun's true longitude
var L = M + 1.916*sind(M) + 0.020*sind(2*M) + 282.634
L %= 360
// Calculate the Sun's right ascension
var RA = atand(0.91764 * tand(L))
RA %= 360
let Lquadrant = (floor(L/90))*90
let RAquadrant = (floor(RA/90))*90
RA += Lquadrant - RAquadrant
RA /= 15
// Calculate the Sun's declination
let sinDec = 0.39782*sind(L)
let cosDec = cosd(asind(sinDec))
// Calculate the Sun's local hour angle
let cosH = (cosd(zenith.rawValue) - sinDec*sind(latitude))/(cosDec*cosd(latitude))
if cosH > 1 { // The sun never rises on this location (on the specified date)
sunriseTime = Double.infinity
sunsetTime = -Double.infinity
} else if cosH < -1 { // The sun never sets on this location (on the specified date)
sunriseTime = -Double.infinity
sunsetTime = Double.infinity
} else {
// Finish calculating H and convert into hours
var H = ( i == 0 ? 360.0 : 0.0 ) + ( i == 0 ? -1.0 : 1.0 )*acosd(cosH)
H /= 15
// Calculate local mean time of rising/setting
let T = H + RA - 0.06571*t - 6.622
// Adjust back to UTC
let UT = T - longitudeHour
// Convert UT value to local time zone of latitude/longitude
let localT = UT + localOffset
if i == 0 { // Add 24 and modulo 24 to be sure that the results is between 0..<24
sunriseTime = (localT + 24)%24
} else {
sunsetTime = (localT + 24)%24
}
}
}
return (sunriseTime, sunsetTime)
}
func sind(valueInDegrees: Double) -> Double {
return sin(valueInDegrees*M_PI/180)
}
func cosd(valueInDegrees: Double) -> Double {
return cos(valueInDegrees*M_PI/180)
}
func tand(valueInDegrees: Double) -> Double {
return tan(valueInDegrees*M_PI/180)
}
func asind(valueInRadians: Double) -> Double {
return asin(valueInRadians)*180/M_PI
}
func acosd(valueInRadians: Double) -> Double {
return acos(valueInRadians)*180/M_PI
}
func atand(valueInRadians: Double) -> Double {
return atan(valueInRadians)*180/M_PI
}
Ans this is how I use the function to determine if it's night or not:
let latitude = ...
let longitude = ...
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
let (sunriseHour, sunsetHour) = sunriseSunsetHoursForLocation(coordinate)
let componetns = NSCalendar.currentCalendar().components([.Hour, .Minute], fromDate: NSDate())
let currentHour = Double(componetns.hour) + Double(componetns.minute)/60
let isNight = currentHour < sunriseHour || currentHour > sunsetHour
I'm not sure why your code to get the offset isn't working (I got the same result). But there's a simpler solution that does work. Just ask the local time zone, using secondsFromGMTForDate. With dates six months apart I get different results:
let now = NSDate()
let future = NSCalendar.currentCalendar().dateByAddingUnit(NSCalendarUnit.Month, value: 6, toDate: now, options: NSCalendarOptions(rawValue: 0))!
let nowOffset = NSTimeZone.localTimeZone().secondsFromGMTForDate(now)/3600
let futureOffset = NSTimeZone.localTimeZone().secondsFromGMTForDate(future)/3600

Adding time Strings in swift

I have an array of timeStrings of the following format:
x Hr(s) xx min.
I need to add these up to give a total. I'm wondering what is the best way to do this?
My thoughts were to find the index of "Hr(s)". Then if i substring between index 0 and the index of "Hr(s)", I have my hrs var and then add 6 to index of "Hr(s)" and find the index of "min" - 1, to give me the min var.
Then I need to take into account if seconds is greater than 60. So if I divide my seconds var by 60 and the answer is great than 1, I add that answer to my hrs var?
Can anyone see any flaws in this logic?
Sample implementation:
JSON response:
{"status":"OK","hrs":[{"scheduleDate":"2015-11-09","userName":"John Doe","company":"Company X","hrsWorked":"0 Hr(s) 42 min"},{"scheduleDate":"2015-11-10","userName":"Jane Doe","company":"Company Y","hrsWorked":"0 Hr(s) 47 min"},{"scheduleDate":"2015-11-10","userName":"Bob loblaw","company":"Company X","hrsWorked":"0 Hr(s) 37 min"},{"scheduleDate":"2015-11-10","userName":"Joe Soap","company":"Company Y","hrsWorked":"0 Hr(s) 50 min"},{"scheduleDate":"2015-11-10","userName":"Test","company":"Company Y","hrsWorked":"0 Hr(s) 40 min"}],"queryStatus":"OK","message":null,"count":5}
var hrsVar = 0
var minsVar = 0
loop through hrsArray{
hrsMinStr = hrsWorkedInJson
if let endHrsIndex = hrsMinStr.lowercaseString.characters.indexOf("Hr(s)") {
print("Index: \(index)")
let hrsStr = Int(hrsMinStr.substringWithRange(Range<String.Index>(start: 0, end: endHrsIndex)))
hrsVar += hrsStr
let minStr = Int(hrsMinStr.substringWithRange(Range<String.Index>(start: endHrsIndex + 1, end: hrsMinStr.length - 3)))
minsVar += minStr
}
}
if minsVar/60 > 1 {
hrsVar = hrsVar + minsVar/60
minsVar = minsVar%60
}
Update
It seems as though I cannot pass in "Hr(s)" and instead only a single character "h". Because of this, I was trying to use the advancedBy(x) method to get the right endIndex. But I'm getting the error:
Cannot invoke initializer for type 'Range<Index>' with an argument list of type '(start: Int, end: String.CharacterView.Index)'
Updated code:
if let endHrsIndex = hrsMinStr.lowercaseString.characters.indexOf("h") {
print("Index: \(endHrsIndex)")
let hrsStr = Int(hrsMinStr.substringWithRange(Range<String.Index>(start: 0, end: endHrsIndex)))
hrsVar += hrsStr
let minStr = Int(hrsMinStr.substringWithRange(Range<String.Index>(start: endHrsIndex.advancedBy(5), end: hrsMinStr.length.characters.count.advancedBy(-3))))
minsVar += minStr
}
I'm really looking for the most efficient approach as possible, so please advise if there is a better way/if you see issues with this approach
import Foundation
let str = "0 Hr(s) 42 min"
let time = str
.stringByReplacingOccurrencesOfString("Hr(s)", withString:":")
.stringByReplacingOccurrencesOfString("min", withString: "")
.stringByReplacingOccurrencesOfString(" ", withString: "")
let t = time.characters.split(Character(":"))
let h = Int(String(t[0])) // 0
let m = Int(String(t[1])) // 1
and sum
import Foundation
var time: [(hours:Int,minutes:Int,seconds:Int)] = []
for i in 0...5 {
let h = Int(arc4random_uniform(24))
let m = Int(arc4random_uniform(60))
let s = Int(arc4random_uniform(60))
time.append((h,m,s))
}
let t = time.reduce(0) { (sum, time: (hours: Int, minutes: Int, seconds: Int)) -> Int in
sum + time.seconds + time.minutes * 60 + time.hours * 60 * 60
}
let seconds = t % 60
let minutes = ((t - seconds) / 60) % 60
let hours = ((t - seconds) / 3660)
time.forEach {
print(String(format: " %6d:%02d:%02d", arguments: [$0.hours,$0.minutes, $0.seconds]))
}
print("-------------------")
print(String(format: "Sum: %6d:%02d:%02d", arguments: [hours,minutes,seconds]))
/*
12:25:04
2:43:36
14:09:35
11:59:43
10:39:19
23:32:14
-------------------
Sum: 74:29:31
*/
You should most likely try using the scanners in your case.
let string = "12 Hr(s) 37 min"
let scanner = NSScanner(string: string)
var min: Int = 0
var hour : Int = 0
scanner.scanInteger(&hour)
scanner.scanString("Hr(s) ", intoString: nil)
scanner.scanInteger(&min)
Or even easier if you create this part in Objective-C:
int min, hour;
sscanf("12 Hr(s) 37 min", "%d Hr(s) %d min", &hour, &min);

Convert string format to another date format

My string format is: M/d/yyyy h:m:s aa
Now, I want to change it in yyyy-MM-ddTHH:mm:ss format.
How can I change it in this format. Please tell me appropriate solution
The method getConvertedDate(String), will do a plain text parsing for conversion.
private String getConvertedDate(String inputDate) {
// extract and adjust Month
int index = inputDate.indexOf('/');
String month = inputDate.substring(0, index);
if (month.length() < 2) {
month = "0" + month;
}
// extract and adjust Day
inputDate = inputDate.substring(index + 1);
index = inputDate.indexOf('/');
String day = inputDate.substring(0, index);
if (day.length() < 2) {
day = "0" + day;
}
// extract Year
inputDate = inputDate.substring(index + 1);
index = inputDate.indexOf(' ');
String year = inputDate.substring(0, index);
// extract Hour
inputDate = inputDate.substring(index + 1);
index = inputDate.indexOf(':');
String hour = inputDate.substring(0, index);
// extract and adjust Minute
inputDate = inputDate.substring(index + 1);
index = inputDate.indexOf(':');
String minute = inputDate.substring(0, index);
if (minute.length() < 2) {
minute = "0" + minute;
}
// extract and adjust Second
inputDate = inputDate.substring(index + 1);
index = inputDate.indexOf(' ');
String second = inputDate.substring(0, index);
if (second.length() < 2) {
second = "0" + second;
}
// extract AM/PM marker
// adjust hour, +12 for PM
inputDate = inputDate.substring(index + 1);
String am_pm_marker = inputDate.substring(0);
if (am_pm_marker.equalsIgnoreCase("pm")) {
int hourValue = 0;
try {
hourValue = Integer.parseInt(hour);
} catch (Exception e) {
}
hourValue += 12;
hour = "" + hourValue;
if (hour.length() < 2) {
hour = "0" + hour;
}
} else {
if (hour.length() < 2) {
hour = "0" + hour;
}
}
String outputDate = year + "-" + month + "-" + day;
outputDate += "T" + hour + ":" + minute + ":" + second;
return outputDate;
}
Sample input and output:
String input = "04/01/2012 9:55:47 pm";
System.out.println("Output: " + getConvertedDate(input));
// Output: 2012-04-01T21:55:47
Date date = (Date)new SimpleDateFormat("M/d/yyyy h:m:s aa").parse(your_string_date);
String finalFormat = new SimpleDateFormat("yyyy-MM-ddTHH:mm:ss").format(date)
Basically the first SimpleDateFormat recognizes your original format and parses it into a Date. Then the second one formats the date object to what you need.
I don't have jdk around to test here, but it should work.
Check this links for format syntax in case something doesn't work:
http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html

Resources