MailCore2 Search Expression with more than two parameters? - mailcore2

How can I search mailcore2 with more than two expressions?
My example below includes exprSinceLastTime as well as exprFrom and exprSubject. But, searchAdd only has room for two parameters.
How can I add additional search expressions such as exprSinceLastTime?
NSTimeInterval oneHour = 3600;
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:oneHour];
MCOIMAPSearchExpression * exprSinceLastTime = [MCOIMAPSearchExpression searchSinceReceivedDate:now];
MCOIMAPSearchExpression * exprFrom = [MCOIMAPSearchExpression searchFrom: #"apple"];
MCOIMAPSearchExpression * exprSubject = [MCOIMAPSearchExpression searchSubject: #"cloudkit"];
MCOIMAPSearchExpression * expr = [MCOIMAPSearchExpression searchAnd: exprFrom other: exprSubject];
MCOIMAPSearchOperation* searchOperation = [session searchExpressionOperationWithFolder: folder expression: expr];

I post the answer below. It was very simple. I had to sleep on the question to think of the obvious answer :-)
NSTimeInterval oneHour = 3600; // magic number! 60 seconds
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:oneHour];
MCOIMAPSearchExpression * exprSinceLastTime = [MCOIMAPSearchExpression searchSinceReceivedDate:now];
MCOIMAPSearchExpression* exprFrom = [MCOIMAPSearchExpression searchFrom: #"youtube"];
MCOIMAPSearchExpression* exprSubject = [MCOIMAPSearchExpression searchSubject: #"video"];
MCOIMAPSearchExpression* expr = [MCOIMAPSearchExpression searchAnd: exprFrom other: exprSubject];
MCOIMAPSearchExpression* expr2 = [MCOIMAPSearchExpression searchAnd: exprSinceLastTime other: expr];
MCOIMAPSearchOperation* searchOperation = [session searchExpressionOperationWithFolder: folder expression: expr2];

Related

How to convert decimal-based time to NSDate?

I have times that are represented as doubles. For example:
8:00am is 8.00
1:30pm is 13.50
6:15pm is 18.25
11:20pm is 23.333
How can I convert the doubles into an NSDate of today?
let input = 13.50
let hour = Int(input)
let minute = Int((input - Double(Int(input))) * 60)
let resultDate = NSCalendar.currentCalendar().dateBySettingHour(hour, minute: minute, second: 0, ofDate: NSDate(), options: nil)!
Get midnight today using this answer : How can I get an NSDate object for today at midnight?
NSDate *date = [NSDate date];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSUInteger preservedComponents = (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit);
date = [calendar dateFromComponents:[calendar components:preservedComponents fromDate:date]];
Then once you have the time at midnight, we will use addTimeInterval to add on the seconds from your decimal value.
int hoursToAdd = (int)timeDecimal;
int minutesToAdd = timeDecimal - hoursToAdd;
int secondsFromHours = hoursToAdd*60*60;
int secondsFromMinutes = minutesToAdd*60;
int totalSeconds = secondsFromHours + secondsFromMinutes;
NSDate *newDate = [date addTimeInterval:totalSeconds];
Should do the trick!
Start with midnight of today and add your amount of hours:
func dateFromDecimalHours(hours: Double) -> NSDate {
let midnight = NSCalendar.currentCalendar().startOfDayForDate(NSDate())
let date = midnight.dateByAddingTimeInterval(round(hours * 3600.0))
return date
}
(Most decimal fractions are not represented exactly by a Double,
that's why the time interval is rounded to seconds.)
Examples/test cases:
let fmt = NSDateFormatter()
fmt.dateFormat = "dd/MM/yyyy hh:mm.ss a"
let d1 = dateFromDecimalHours(18.25)
println(fmt.stringFromDate(d1)) // 07/05/2015 06:15.00 pm
let d2 = dateFromDecimalHours(23.3333)
println(fmt.stringFromDate(d2)) // 07/05/2015 11:20.00 pm
let d3 = dateFromDecimalHours(1.0 + 23.0/60.0 + 45.0/3600.0)
println(fmt.stringFromDate(d3)) // 07/05/2015 01:23.45 am

Objective-C: Separate number right/left of decimal

I am trying to separate the left and right numbers from a float so I can turn each into a string. So for example, 5.11, I need to be able to turn 5 into a string, and 11 into another string.
// from float: 5.11
NSString * leftNumber = #"5";
NSString * rightNumber = #"11";
From this, I can turn 5.11 into 5' 11".
One way:
Use stringWithFormat to convert to string "5.11".
Use componentsSeparatedByString to seperate into an array of "5" and "11".
Combine with stringWithFormat.
You could use NSString stringWithFormat and math functions for that:
float n = 5.11;
NSString * leftNumber = [NSString stringWithFormat:#"%0.0f", truncf(n)];
NSString * rightNumber = [[NSString stringWithFormat:#"%0.2f", fmodf(n, 1.0)] substringFromIndex:2];
NSLog(#"'%#' '%#'", leftNumber, rightNumber);
However, this is not ideal, especially for representing lengths in customary units, because 0.11 ft is not 11 inches. You would be better off representing the length as an integer in the smallest units that you support (say, for example, 1/16-th of an inch) and then convert it to the actual length for display purposes. In this representation 5 ft 11 in would be 5*12*16 + 11*16 = 1136.
You could use a number formatter as such
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
formatter.decimalSeparator = #"'";
formatter.positiveSuffix = #"\"";
formatter.alwaysShowsDecimalSeparator = true;
NSString *numberString = [formatter stringFromNumber:#(5.11)];
// Output : 5'11"

NSNumberFormatter with significant digits formats 0.0 incorrectly

I've got an NSNumberFormatter set up to format using significant digits, so it should only show as many decimal digits as are necessary to correctly display the value.
When it is used to format 7.0 it works exactly as expected and produces #"7", but when it is used to format 0.0 the formatter produces #"0.0" instead of #"0" as would be expected.
NSNumberFormatter *doubleValF = [[NSNumberFormatter alloc] init];
[doubleValF setNumberStyle:NSNumberFormatterDecimalStyle];
[doubleValF setRoundingMode:NSNumberFormatterRoundHalfUp];
doubleValF.maximumFractionDigits = 9;
doubleValF.minimumFractionDigits = 0;
doubleValF.minimumSignificantDigits = 0;
doubleValF.maximumSignificantDigits = 30;
[doubleValF setUsesSignificantDigits:YES];
double value1 = 0.0;
NSString *value1String = [doubleValF stringFromNumber:[NSNumber numberWithDouble:value1]];
double value2 = 7.0;
NSString *value2String = [doubleValF stringFromNumber:[NSNumber numberWithDouble:value2]];
NSLog(#"value1=%#", value1String);
NSLog(#"value2=%#", value2String);
When I run this code, I get the following output:
2012-12-15 15:57:03.425 StackOverflowTests[41701:11303] value1=0.0
2012-12-15 15:57:03.426 StackOverflowTests[41701:11303] value2=7
Following David's LaMacchia's post, just check for a zero value and set the sig fig mode:
if(fabs(value) < 1e-6) {
self.numberLabelFormatter.usesSignificantDigits = NO;
}
else {
self.numberLabelFormatter.usesSignificantDigits = YES;
}
self.numberLabel.text = [self.numberLabelFormatter stringFromNumber:[NSNumber numberWithDouble:value]];
This may not be the correct method, but it works for me.
The issue is related to your having set usesSignificantDigits to YES. I believe the trailing digit, in 0.0, is considered significant.
There's a good discussion of a related issue here: https://stackoverflow.com/a/13110633/1435955
Try to set zeroSymbol property of number formatter to #"0".
doubleValF.zeroSymbol = #"0";

LDAP Date to NSDate

I am trying to parse the pwdLastSet value from NSTask response when I do an ldapsearch. I've successfully extracted the value (129875475241190194) and I am trying to convert it to an NSDate Object.
Reference: http://www.chrisnowell.com/information_security_tools/date_converter/Windows_active_directory_date_converter.asp
I tried to extract the Javascript code from the page above and convert it but I am getting a different date.
int iYearsFrom1601to1970 = 1970 - 1601;
int iDaysFrom1601to1970 = iYearsFrom1601to1970 * 365;
iDaysFrom1601to1970 += (int)(iYearsFrom1601to1970 / 4); // leap years
iDaysFrom1601to1970 -= 3; // non-leap centuries (1700,1800,1900). 2000 is a leap century
float iSecondsFrom1601to1970 = iDaysFrom1601to1970 * 24 * 60 * 60;
int iTotalSecondsSince1601 = (int)(129875475241190194 / 10000000);
float iTotalSecondsSince1970 = iTotalSecondsSince1601 - iSecondsFrom1601to1970;
NSDate *date = [NSDate dateWithTimeIntervalSince1970:iTotalSecondsSince1970];
Any help would be appreciated.
Thanks!
Here's how I would do it:
NSDateComponents *base = [[NSDateComponents alloc] init];
[base setDay:1];
[base setMonth:1];
[base setYear:1601];
[base setEra:1]; // AD
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *baseDate = [gregorian dateFromComponents:base];
[base release];
[gregorian release];
NSTimeInterval timestamp = 129875475241190194.0 / 10000000.0;
NSDate *finalDate = [baseDate dateByAddingTimeInterval:timestamp];
This gives me a finalDate of 2012-07-24 03:58:22 +0000.
Since the timestamp is a time interval since Jan 1, 1601 at 00:00 UTC, you can use the -dateByAddingTimeInterval: method on NSDate to add the timestamp to the base date to get the final NSDate.
Once you've done that, you can run it through an NSDateFormatter to format it for display.
Assuming the, well, daring conversion between the basetimes is correct: actually looking at the warnings, instead of casting them away, might actually help:
int main(void)
{
int iTotalSecondsSince1601 = (129875475241190194 / 10000000);
return 0;
}
stieber#gatekeeper:~$ clang++ Test.cpp
Test.cpp:4:8: warning: implicit conversion from 'long' to 'int' changes value from 12987547524 to 102645636
....
That should account for a good deal of the difference...
Try this
NSTimeInterval value = 129875475241190194;
// instead of trying to compute seconds between 1601 and 1970
const NSTimeInterval EPOCH = 11644473600;
const NSTimeInterval NANO = 10000000;
NSTimeInterval seconds = value / NANO - EPOCH;
NSDate *answer = [NSDate dateWithTimeIntervalSince1970:seconds];
Also this is reason you don't want to calculate seconds since 1601: ...in the last millennium, 1600 and 2000 were leap years, but 1700, 1800 and 1900 were not. Excerpt from Wikipedia on Gregorian calendar.
The value for EPOCH is explained on Convert Active Directory "LastLogon:" time to (UNIX) readable time
.
Note: The information about accountExpires which starts from 12-31-1601 (11644473600). The values lastLogon and lastLogonTimeStamp however use 01-01-1601 as the date to calculate this value (11676009600).

How to convert an NSTimeInterval (seconds) into minutes

I've got an amount of seconds that passed from a certain event. It's stored in a NSTimeInterval data type.
I want to convert it into minutes and seconds.
For example I have: "326.4" seconds and I want to convert it into the following string:
"5:26".
What is the best way to achieve this goal?
Thanks.
Brief Description
The answer from Brian Ramsay is more convenient if you only want to convert to minutes.
If you want Cocoa API do it for you and convert your NSTimeInterval not only to minutes but also to days, months, week, etc,... I think this is a more generic approach
Use NSCalendar method:
(NSDateComponents *)components:(NSUInteger)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSUInteger)opts
"Returns, as an NSDateComponents object using specified components, the difference between two supplied dates". From the API documentation.
Create 2 NSDate whose difference is the NSTimeInterval you want to convert. (If your NSTimeInterval comes from comparing 2 NSDate you don't need to do this step, and you don't even need the NSTimeInterval).
Get your quotes from NSDateComponents
Sample Code
// The time interval
NSTimeInterval theTimeInterval = 326.4;
// Get the system calendar
NSCalendar *sysCalendar = [NSCalendar currentCalendar];
// Create the NSDates
NSDate *date1 = [[NSDate alloc] init];
NSDate *date2 = [[NSDate alloc] initWithTimeInterval:theTimeInterval sinceDate:date1];
// Get conversion to months, days, hours, minutes
unsigned int unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit;
NSDateComponents *conversionInfo = [sysCalendar components:unitFlags fromDate:date1 toDate:date2 options:0];
NSLog(#"Conversion: %dmin %dhours %ddays %dmoths",[conversionInfo minute], [conversionInfo hour], [conversionInfo day], [conversionInfo month]);
[date1 release];
[date2 release];
Known issues
Too much for just a conversion, you are right, but that's how the API works.
My suggestion: if you get used to manage your time data using NSDate and NSCalendar, the API will do the hard work for you.
pseudo-code:
minutes = floor(326.4/60)
seconds = round(326.4 - minutes * 60)
All of these look more complicated than they need to be! Here is a short and sweet way to convert a time interval into hours, minutes and seconds:
NSTimeInterval timeInterval = 326.4;
long seconds = lroundf(timeInterval); // Since modulo operator (%) below needs int or long
int hour = seconds / 3600;
int mins = (seconds % 3600) / 60;
int secs = seconds % 60;
Note when you put a float into an int, you get floor() automatically, but you can add it to the first two if if makes you feel better :-)
Forgive me for being a Stack virgin... I'm not sure how to reply to Brian Ramsay's answer...
Using round will not work for second values between 59.5 and 59.99999. The second value will be 60 during this period. Use trunc instead...
double progress;
int minutes = floor(progress/60);
int seconds = trunc(progress - minutes * 60);
If you're targeting at or above iOS 8 or OS X 10.10, this just got a lot easier. The new NSDateComponentsFormatter class allows you to convert a given NSTimeInterval from its value in seconds to a localized string to show the user. For example:
Objective-C
NSTimeInterval interval = 326.4;
NSDateComponentsFormatter *componentFormatter = [[NSDateComponentsFormatter alloc] init];
componentFormatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
componentFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropAll;
NSString *formattedString = [componentFormatter stringFromTimeInterval:interval];
NSLog(#"%#",formattedString); // 5:26
Swift
let interval = 326.4
let componentFormatter = NSDateComponentsFormatter()
componentFormatter.unitsStyle = .Positional
componentFormatter.zeroFormattingBehavior = .DropAll
if let formattedString = componentFormatter.stringFromTimeInterval(interval) {
print(formattedString) // 5:26
}
NSDateCompnentsFormatter also allows for this output to be in longer forms. More info can be found in NSHipster's NSFormatter article. And depending on what classes you're already working with (if not NSTimeInterval), it may be more convenient to pass the formatter an instance of NSDateComponents, or two NSDate objects, which can be done as well via the following methods.
Objective-C
NSString *formattedString = [componentFormatter stringFromDate:<#(NSDate *)#> toDate:<#(NSDate *)#>];
NSString *formattedString = [componentFormatter stringFromDateComponents:<#(NSDateComponents *)#>];
Swift
if let formattedString = componentFormatter.stringFromDate(<#T##startDate: NSDate##NSDate#>, toDate: <#T##NSDate#>) {
// ...
}
if let formattedString = componentFormatter.stringFromDateComponents(<#T##components: NSDateComponents##NSDateComponents#>) {
// ...
}
Brian Ramsay’s code, de-pseudofied:
- (NSString*)formattedStringForDuration:(NSTimeInterval)duration
{
NSInteger minutes = floor(duration/60);
NSInteger seconds = round(duration - minutes * 60);
return [NSString stringWithFormat:#"%d:%02d", minutes, seconds];
}
Here's a Swift version:
func durationsBySecond(seconds s: Int) -> (days:Int,hours:Int,minutes:Int,seconds:Int) {
return (s / (24 * 3600),(s % (24 * 3600)) / 3600, s % 3600 / 60, s % 60)
}
Can be used like this:
let (d,h,m,s) = durationsBySecond(seconds: duration)
println("time left: \(d) days \(h) hours \(m) minutes \(s) seconds")
NSDate *timeLater = [NSDate dateWithTimeIntervalSinceNow:60*90];
NSTimeInterval duration = [timeLater timeIntervalSinceNow];
NSInteger hours = floor(duration/(60*60));
NSInteger minutes = floor((duration/60) - hours * 60);
NSInteger seconds = floor(duration - (minutes * 60) - (hours * 60 * 60));
NSLog(#"timeLater: %#", [dateFormatter stringFromDate:timeLater]);
NSLog(#"time left: %d hours %d minutes %d seconds", hours,minutes,seconds);
Outputs:
timeLater: 22:27
timeLeft: 1 hours 29 minutes 59 seconds
Since it's essentially a double...
Divide by 60.0 and extract the integral part and the fractional part.
The integral part will be the whole number of minutes.
Multiply the fractional part by 60.0 again.
The result will be the remaining seconds.
Remember that the original question is about a string output, not pseudo-code or individual string components.
I want to convert it into the following string: "5:26"
Many answers are missing the internationalization issues, and most doing the math computations by hand. All just so 20th century...
Do not do the Math yourself (Swift 4)
let timeInterval: TimeInterval = 326.4
let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.unitsStyle = .positional
if let formatted = dateComponentsFormatter.string(from: timeInterval) {
print(formatted)
}
5:26
Leverage on libraries
If you really want individual components, and pleasantly readable code, check out SwiftDate:
import SwiftDate
...
if let minutes = Int(timeInterval).seconds.in(.minute) {
print("\(minutes)")
}
5
Credits to #mickmaccallum and #polarwar for adequate usage of DateComponentsFormatter
How I did this in Swift (including the string formatting to show it as "01:23"):
let totalSeconds: Double = someTimeInterval
let minutes = Int(floor(totalSeconds / 60))
let seconds = Int(round(totalSeconds % 60))
let timeString = String(format: "%02d:%02d", minutes, seconds)
NSLog(timeString)
Swift 2 version
extension NSTimeInterval {
func toMM_SS() -> String {
let interval = self
let componentFormatter = NSDateComponentsFormatter()
componentFormatter.unitsStyle = .Positional
componentFormatter.zeroFormattingBehavior = .Pad
componentFormatter.allowedUnits = [.Minute, .Second]
return componentFormatter.stringFromTimeInterval(interval) ?? ""
}
}
let duration = 326.4.toMM_SS()
print(duration) //"5:26"