NSDate를 가장 가까운 5 분으로 반올림
예를 들어
NSDate *curDate = [NSDate date];
그 값은 오전 9시 13 분입니다. curDate의 연도, 월, 일 부분을 사용하지 않습니다.
내가 얻고 싶은 것은 시간 값이 9:15 인 날짜입니다. 시간 값이 9:16이면 9:20 등으로 진행하고 싶습니다.
NSDate로 어떻게 할 수 있습니까?
분 값을 가져 와서 5로 반올림하여 다음으로 높은 5 분 단위를 얻고, 5를 곱하여 분 단위로 되돌리고 새로운 NSDate를 구성합니다.
NSDateComponents *time = [[NSCalendar currentCalendar]
components:NSHourCalendarUnit | NSMinuteCalendarUnit
fromDate:curDate];
NSInteger minutes = [time minute];
float minuteUnit = ceil((float) minutes / 5.0);
minutes = minuteUnit * 5.0;
[time setMinute: minutes];
curDate = [[NSCalendar currentCalendar] dateFromComponents:time];
내 해결책은 다음과 같습니다.
NSTimeInterval seconds = round([date timeIntervalSinceReferenceDate]/300.0)*300.0;
NSDate *rounded = [NSDate dateWithTimeIntervalSinceReferenceDate:seconds];
몇 가지 테스트를했는데 Voss의 솔루션보다 약 10 배 빠릅니다. 1M 반복으로 약 3.39 초가 걸렸습니다. 이것은 0.38 초 만에 수행되었습니다. J3RM의 솔루션은 0.50 초가 걸렸습니다. 메모리 사용량도 가장 낮아야합니다.
성능이 모든 것이 아니라 한 줄짜리입니다. 또한 나눗셈과 곱셈으로 반올림을 쉽게 제어 할 수 있습니다.
수정 : 질문에 답하려면 다음을 사용 ceil
하여 올바르게 반올림 할 수 있습니다 .
NSTimeInterval seconds = ceil([date timeIntervalSinceReferenceDate]/300.0)*300.0;
NSDate *rounded = [NSDate dateWithTimeIntervalSinceReferenceDate:seconds];
편집 : Swift의 확장 :
public extension Date {
public func round(precision: TimeInterval) -> Date {
return round(precision: precision, rule: .toNearestOrAwayFromZero)
}
public func ceil(precision: TimeInterval) -> Date {
return round(precision: precision, rule: .up)
}
public func floor(precision: TimeInterval) -> Date {
return round(precision: precision, rule: .down)
}
private func round(precision: TimeInterval, rule: FloatingPointRoundingRule) -> Date {
let seconds = (self.timeIntervalSinceReferenceDate / precision).rounded(rule) * precision;
return Date(timeIntervalSinceReferenceDate: seconds)
}
}
와우 저, 여기에 많은 답변이 있지만 많은 답변이 길거나 이해하기 어렵 기 때문에 도움이 될 수 있도록 2 센트를 투자하겠습니다. 이 NSCalendar
클래스는 안전하고 간결한 방식으로 필요한 기능을 제공합니다. 여기에 시간 간격 초, 반올림 또는 아무것도 곱하지 않고 나를 위해 작동하는 솔루션이 있습니다. NSCalendar
윤일 / 년, 기타 시간 및 날짜 이상을 고려합니다. (스위프트 2.2)
let calendar = NSCalendar.currentCalendar()
let rightNow = NSDate()
let interval = 15
let nextDiff = interval - calendar.component(.Minute, fromDate: rightNow) % interval
let nextDate = calendar.dateByAddingUnit(.Minute, value: nextDiff, toDate: rightNow, options: []) ?? NSDate()
NSDate
필요한 경우 확장에 추가 하거나 필요한 경우 새 NSDate
인스턴스를 반환하는 자유 형식 함수로 추가 할 수 있습니다 . 이것이 필요한 모든 사람에게 도움이되기를 바랍니다.
Swift 3 업데이트
let calendar = Calendar.current
let rightNow = Date()
let interval = 15
let nextDiff = interval - calendar.component(.minute, from: rightNow) % interval
let nextDate = calendar.date(byAdding: .minute, value: nextDiff, to: rightNow) ?? Date()
Chris '와 swift3를 기반으로하는 것은 어떻습니까?
import UIKit
enum DateRoundingType {
case round
case ceil
case floor
}
extension Date {
func rounded(minutes: TimeInterval, rounding: DateRoundingType = .round) -> Date {
return rounded(seconds: minutes * 60, rounding: rounding)
}
func rounded(seconds: TimeInterval, rounding: DateRoundingType = .round) -> Date {
var roundedInterval: TimeInterval = 0
switch rounding {
case .round:
roundedInterval = (timeIntervalSinceReferenceDate / seconds).rounded() * seconds
case .ceil:
roundedInterval = ceil(timeIntervalSinceReferenceDate / seconds) * seconds
case .floor:
roundedInterval = floor(timeIntervalSinceReferenceDate / seconds) * seconds
}
return Date(timeIntervalSinceReferenceDate: roundedInterval)
}
}
// Example
let nextFiveMinuteIntervalDate = Date().rounded(minutes: 5, rounding: .ceil)
print(nextFiveMinuteIntervalDate)
이것이 최선의 해결책이라고 생각하지만 이전 포스터 코드를 기반으로 한 내 의견입니다. 가장 가까운 5 분 표시로 반올림합니다. 이 코드는 날짜 구성 요소 솔루션보다 훨씬 적은 메모리를 사용해야합니다. 훌륭합니다. 방향을 알려 주셔서 감사합니다.
+(NSDate *) dateRoundedDownTo5Minutes:(NSDate *)dt{
int referenceTimeInterval = (int)[dt timeIntervalSinceReferenceDate];
int remainingSeconds = referenceTimeInterval % 300;
int timeRoundedTo5Minutes = referenceTimeInterval - remainingSeconds;
if(remainingSeconds>150)
{/// round up
timeRoundedTo5Minutes = referenceTimeInterval +(300-remainingSeconds);
}
NSDate *roundedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)timeRoundedTo5Minutes];
return roundedDate;
}
샘플 감사합니다. 아래에 5 분에 가까운 코드를 추가했습니다.
-(NSDate *)roundDateTo5Minutes:(NSDate *)mydate{
// Get the nearest 5 minute block
NSDateComponents *time = [[NSCalendar currentCalendar]
components:NSHourCalendarUnit | NSMinuteCalendarUnit
fromDate:mydate];
NSInteger minutes = [time minute];
int remain = minutes % 5;
// if less then 3 then round down
if (remain<3){
// Subtract the remainder of time to the date to round it down evenly
mydate = [mydate addTimeInterval:-60*(remain)];
}else{
// Add the remainder of time to the date to round it up evenly
mydate = [mydate addTimeInterval:60*(5-remain)];
}
return mydate;
}
Most replies here are unfortunately not perfectly correct (even though they seem to work quite well for most users), as they either rely on the current active system calendar to be a Gregorian calendar (which may not be the case) or upon the fact that leap seconds don't exist and/or will always be ignored by OS X an iOS. The following code works copy&paste, is guaranteed to be correct and it makes no such assumptions (and thus will also not break in the future if Apple changes leap seconds support, as in that case NSCalendar will have to correctly support them as well):
{
NSDate * date;
NSUInteger units;
NSCalendar * cal;
NSInteger minutes;
NSDateComponents * comp;
// Get current date
date = [NSDate date];
// Don't rely that `currentCalendar` is a
// Gregorian calendar that works the way we are used to.
cal = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar
];
[cal autorelease]; // Delete that line if using ARC
// Units for the day
units = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
// Units for the time (seconds are irrelevant)
units |= NSHourCalendarUnit | NSMinuteCalendarUnit;
// Split current date into components
comp = [cal components:units fromDate:date];
// Get the minutes,
// will be a number between 0 and 59.
minutes = [comp minute];
// Unless it is a multiple of 5...
if (minutes % 5) {
// ... round up to the nearest multiple of 5.
minutes = ((minutes / 5) + 1) * 5;
}
// Set minutes again.
// Minutes may now be a value between 0 and 60,
// but don't worry, NSCalendar knows how to treat overflows!
[comp setMinute:minutes];
// Convert back to date
date = [cal dateFromComponents:comp];
}
현재 시간이 이미 5 분의 배수 인 경우 코드는 시간을 변경하지 않습니다. 원래 질문은이 경우를 명시 적으로 지정하지 않았습니다. 코드가 항상 다음 5 분의 배수로 반올림되는 경우 테스트를 제거 if (minutes % 5) {
하면 항상 반올림됩니다.
https://forums.developer.apple.com/thread/92399
Apple 직원의 전체 및 자세한 답변은 링크를 참조하십시오. 클릭을 저장하기 위해 솔루션은 다음과 같습니다.
let original = Date()
let rounded = Date(timeIntervalSinceReferenceDate:
(original.timeIntervalSinceReferenceDate / 300.0).rounded(.toNearestOrEven) * 300.0)
나는 방금 내 앱을 위해 이것을 실험하기 시작했고 다음을 생각해 냈습니다. 그것은 Swift에 있지만 Swift를 모르더라도 개념을 충분히 이해할 수 있어야합니다.
func skipToNextEvenFiveMinutesFromDate(date: NSDate) -> NSDate {
var componentMask : NSCalendarUnit = (NSCalendarUnit.CalendarUnitYear | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitHour | NSCalendarUnit.CalendarUnitMinute)
var components = NSCalendar.currentCalendar().components(componentMask, fromDate: date)
components.minute += 5 - components.minute % 5
components.second = 0
if (components.minute == 0) {
components.hour += 1
}
return NSCalendar.currentCalendar().dateFromComponents(components)!
}
결과는 내 놀이터에서 올바르게 보입니다. 여기서 자정에 가까워지고 새해에 가까워지는 등 다양한 사용자 지정 날짜를 삽입합니다.
편집 : Swift2 지원 :
func skipToNextEvenFiveMinutesFromDate(date: NSDate) -> NSDate {
let componentMask : NSCalendarUnit = ([NSCalendarUnit.Year , NSCalendarUnit.Month , NSCalendarUnit.Day , NSCalendarUnit.Hour ,NSCalendarUnit.Minute])
let components = NSCalendar.currentCalendar().components(componentMask, fromDate: date)
components.minute += 5 - components.minute % 5
components.second = 0
if (components.minute == 0) {
components.hour += 1
}
return NSCalendar.currentCalendar().dateFromComponents(components)!
}
다음은 ayianni의 래퍼 아이디어를 사용하여 원래 문제 (반올림)에 대한 내 솔루션입니다.
-(NSDate *)roundDateToCeiling5Minutes:(NSDate *)mydate{
// Get the nearest 5 minute block
NSDateComponents *time = [[NSCalendar currentCalendar]
components:NSHourCalendarUnit | NSMinuteCalendarUnit
fromDate:mydate];
NSInteger minutes = [time minute];
int remain = minutes % 5;
// Add the remainder of time to the date to round it up evenly
mydate = [mydate addTimeInterval:60*(5-remain)];
return mydate;
}
NSCalendar를 사용하여 최대 30 분 동안 반올림하는 Swift 일반 솔루션이 하나 더 있습니다.
extension NSDate {
func nearest(minutes: Int) -> NSDate {
assert(minutes <= 30, "nearest(m) suppport rounding up to 30 minutes");
let cal = NSCalendar.currentCalendar();
var time = cal.components(.CalendarUnitMinute | .CalendarUnitSecond, fromDate: self);
let rem = time.minute % minutes
if rem > 0 {
time.minute = minutes - rem;
}
time.second = -time.second;
time.nanosecond = -time.nanosecond //updated 7.07.15
let date = cal.dateByAddingComponents(time, toDate: self, options: NSCalendarOptions(0));
return date!;
}
}
이것을 직접 찾고 있었지만 위의 예를 사용하여 0001 년 날짜를 얻었습니다.
여기에 smorgan의 더 우아한 모드 제안과 통합 된 내 대안이 있지만 아직 누출 테스트를하지 않았습니다.
NSDate *myDate = [NSDate date];
// Get the nearest 5 minute block
NSDateComponents *time = [[NSCalendar currentCalendar] components:NSHourCalendarUnit | NSMinuteCalendarUnit
fromDate:myDate];
NSInteger minutes = [time minute];
int remain = minutes % 5;
// Add the remainder of time to the date to round it up evenly
myDate = [myDate addTimeInterval:60*(5-remain)];
@ J3RM의 솔루션을 NSDate 클래스의 Swift 확장으로 다시 작성했습니다. 여기에서 가장 가까운 15 분 간격으로 날짜를 반올림합니다.
extension NSDate
{
func nearestFifteenthMinute() -> NSDate!
{
let referenceTimeInterval = Int(self.timeIntervalSinceReferenceDate)
let remainingSeconds = referenceTimeInterval % 900
var timeRoundedTo5Minutes = referenceTimeInterval - remainingSeconds
if remainingSeconds > 450
{
timeRoundedTo5Minutes = referenceTimeInterval + (900 - remainingSeconds)
}
let roundedDate = NSDate.dateWithTimeIntervalSinceReferenceDate(NSTimeInterval(timeRoundedTo5Minutes))
return roundedDate
}
}
나는 이것이 오래된 스레드라는 것을 알고 있지만 더 최근의 답변이 있기 때문에 NSDate를 가장 가까운 5 분 간격으로 반올림하는 데 사용하는 유틸리티 방법을 공유 할 것입니다.
I use this to populate a UITextField with the current UIDatePicker date when it becomes FirstResponder. You can't just use [NSDate date] when the UIDatePicker is configured with something other than a 1 minute interval. Mine are configured with 5 minute intervals.
+ (NSDate *)roundToNearest5MinuteInterval {
NSDate *ceilingDate = [NSDate dateWithTimeIntervalSinceReferenceDate:ceil([[NSDate date] timeIntervalSinceReferenceDate]/300.0)*300.0];
NSDate *floorDate = [NSDate dateWithTimeIntervalSinceReferenceDate:floor([[NSDate date] timeIntervalSinceReferenceDate]/300.0)*300.0];
NSTimeInterval ceilingInterval = [ceilingDate timeIntervalSinceNow];
NSTimeInterval floorInterval = [floorDate timeIntervalSinceNow];
if (fabs(ceilingInterval) < fabs(floorInterval)) {
return ceilingDate;
} else {
return floorDate;
}
}
Ignoring the title of the question and reading what @aler really wants to accomplish (rounding UP to the nearest 5 minute). All you have to do is the following:
NSDate *ceilingDate = [NSDate dateWithTimeIntervalSinceReferenceDate:ceil([[NSDate date] timeIntervalSinceReferenceDate]/300.0)*300.0];
I'm not sure how efficient NSDateComponents are, but if you just want to deal with the NSDate itself it can give you values based on seconds which can then be manipulated.
For example, this method rounds down to the nearest minute. Change the 60 to 300 and it will round down to nearest 5 minutes.
+ (NSDate *)dateRoundedDownToMinutes:(NSDate *)date {
// Strip miliseconds by converting to int
int referenceTimeInterval = (int)[date timeIntervalSinceReferenceDate];
int remainingSeconds = referenceTimeInterval % 60;
int timeRoundedDownToMinutes = referenceTimeInterval - remainingSeconds;
NSDate *roundedDownDate = [NSDate dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)timeRoundedDownToMinutes];
return roundedDownDate;
}
This is a generic solution which rounds up to the nearest input 'mins':
+(NSDate *)roundUpDate:(NSDate *)aDate toNearestMins:(NSInteger)mins
{
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSUIntegerMax fromDate:aDate];
NSInteger dateMins = components.minute;
dateMins = ((dateMins+mins)/mins)*mins;
[components setMinute:dateMins];
[components setSecond:0];
return [[NSCalendar currentCalendar] dateFromComponents:components];
}
- (NSDate *)roundDateToNearestFiveMinutes:(NSDate *)date
{
NSDateComponents *time = [[NSCalendar currentCalendar]
components:NSHourCalendarUnit | NSMinuteCalendarUnit
fromDate:date];
NSInteger minutes = [time minute];
float minuteUnit = ceil((float) minutes / 5.0);
minutes = minuteUnit * 5.0;
[time setMinute: minutes];
return [[NSCalendar currentCalendar] dateFromComponents:time];
}
Even shorter... limit to seconds:
let seconds = ceil(Date().timeIntervalSinceReferenceDate/300.0)*300.0
let roundedDate = Date(timeIntervalSinceReferenceDate: seconds)
ReferenceURL : https://stackoverflow.com/questions/1149256/round-nsdate-to-the-nearest-5-minutes
'programing' 카테고리의 다른 글
쉼표와 포인트를 사용하여 문자열을 이중으로 구문 분석 (0) | 2021.01.16 |
---|---|
Android : APK 설치 중 오류 (0) | 2021.01.16 |
양식 요소에서 탭 포커스 비활성화 (0) | 2021.01.16 |
for 루프에서 ++ i 또는 i ++ ?? (0) | 2021.01.16 |
어댑터에서 활동을 완료하는 방법 ..? (0) | 2021.01.16 |