This is the follow up of a previous question of mine.
In a nutshell, I am trying to follow this tutorial step-by-step: https://jtauber.github.io/mars-clock/ to get to Coordinated Mars Time, but I got stuck right before the end. My code works fine up until the end (some values are more accurate than in the tutorial because I went back to the source from NASA: https://www.giss.nasa.gov/tools/mars24/help/algorithm.html ):
double millis = ( [[NSDate date] timeIntervalSince1970] * 1000 );
NSLog(#"millis: %f", millis);
double JDUT = ( 2440587.5 + (millis / 86400000) );
NSLog(#"JDUT: %f", JDUT);
double JDTT = ( JDUT + (37 +32.184) / 86400);
NSLog(#"JDTT: %f", JDTT);
double J2000Epoch = ( JDTT - 2451545.0 );
NSLog(#"J2000Epoch: %f", J2000Epoch);
double MSD = ( (( J2000Epoch - 4.5 ) / 1.0274912517) + 44796.0 - 0.0009626 );
NSLog(#"MSD: %f", MSD);
The only step remaining is actually calculating Coordinated Mars Time, using this equation:
MTC = mod24 { 24 h × MSD }
The problem is that I have no idea how. I tried to use modf( (double), (double *) ) but no idea how it actually works. I tried it the way below, but it gave me an incorrect answer (obviously as I have really no idea what I am doing). :(
double MSD24 = (24 * MSD);
double MCT = modf(24, &MSD24);
NSLog(#"MCT: %f", MCT); // Result: 0.000000
Any help would be much appreciated. Thank you very much!
p.s.: Notice that I use Objective-C; I do not understand swift unfortunately! :(
Carrying on from the code you gave, I tried:
CGFloat MTC = fmod(24 * MSD, 24);
and got
// 19.798515
which was right according to the web page you cited at the moment I tried it.
The sort of thing his page actually shows, e.g. "19:49:38" or whatever (at the time I tried it), is merely a string representation of that number, treating it as a number of hours and just dividing it up into minutes and seconds in the usual way. Which, I suppose, brings us to the second part of your question, i.e. how to convert a number of hours into an hours-minutes-seconds representation? But that is a simple matter, dealt with many times here. See NSNumber of seconds to Hours, minutes, seconds for example.
So, carrying on once again, I tried this:
CGFloat secs = MTC*3600;
NSDate* d = [NSDate dateWithTimeIntervalSince1970:secs];
NSDateFormatter* df = [NSDateFormatter new];
df.dateFormat = #"HH:mm:ss";
df.timeZone = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
NSString* result = [df stringFromDate:d];
NSLog(#"%#", result); // 20:10:20
...which is exactly the same as his web page was showing at that moment.
And here's a Swift version for those who would like to know what the "mean time" is on Mars right now:
let millis = Date().timeIntervalSince1970 * 1000
let JDUT = 2440587.5 + (millis / 86400000)
let JDTT = JDUT + (37 + 32.184) / 86400
let J2000Epoch = ( JDTT - 2451545 )
let MSD = (( J2000Epoch - 4.5 ) / 1.0274912517) + 44796.0 - 0.0009626
let MTC = (24 * MSD).truncatingRemainder(dividingBy: 24)
let d = Date(timeIntervalSince1970: MTC*3600)
let df = DateFormatter()
df.dateFormat = "HH:mm:ss"
df.timeZone = TimeZone(abbreviation: "GMT")!
df.string(from:d)
Related
Suppose my business hours are from 7am to 7pm, then default selection of time date is :
A) During business hours, a hour later than current time
B) After business hour, 7 am the next business day.
How will you calculate value for Minimum and maximum date ??
Sol -A)
NSDate *minDate = [[NSDate date]dateByAddingTimeInterval:60 * 60 *1];
NSDate *maxDate = [[NSDate date]dateByAddingTimeInterval:60 * 60 * 24 * 2];
Is above solution for (A) is correct ?? is there any other way
Can anyone provide solution for (B) ??
Please provide proper programming code in objective C with explanation ??
Look at this code:
var timepenalty = UInt8(0)
var currentTime = NSDate.timeIntervalSinceReferenceDate()
// Find the difference between current time and start time
var elapsedTime: NSTimeInterval = currentTime - startTime
let adjustedTime = UInt8(timepenalty + elapsedTime)
error-
"Could not find an overload for "+" that accepts the requested arguments.
"
This is for a game that adds time to the stopwatch-style timer, every time the player makes a mistake. The code works when I just use an integer instead of the elapsedTime variable as so:
let adjustedTime = UInt8(elapsedTime + 5)
but replacing 5 with a variable gives an error.
Here's the full code for the updateTime function:
func updateTime() {
var currentTime = NSDate.timeIntervalSinceReferenceDate()
// Find the difference between current time and start time
var elapsedTime: NSTimeInterval = currentTime - startTime
let adjustedTime = UInt8(timepenalty + elapsedTime)
// calculate the minutes in elapsed time
let minutes = UInt8(elapsedTime / 60.0)
elapsedTime -= (NSTimeInterval(minutes) * 60)
// calculate the seconds in elapsed time
seconds = UInt8(elapsedTime)
elapsedTime -= NSTimeInterval(seconds)
// seconds += timepenalty
// find out the fraction of millisends to be displayed
let fraction = UInt8(elapsedTime * 100)
// if seconds > 20 {
// exceedMsgLabel.text = "超过20秒了"
// }
// add the leading zero for minutes, seconds and millseconds and store them as string constants
let startMinutes = minutes > 9 ? String(minutes):"0" + String(minutes)
let startSeconds = seconds > 9 ? String(seconds):"0" + String(seconds)
let startFraction = fraction > 9 ? String(fraction):"0" + String(fraction)
displayTimeLabel.text = "\(startMinutes):\(startSeconds):\(startFraction)"
var penalty = String(timepenalty)
penaltylabel.text = "+ " + penalty
}
#David's code is good, but I'd strongly recommend that you make adjustedTime be an NSTimeInterval. It is a time interval, and that's what the type is for. Then all your casting issues go away.
The UInt8 type is reserved for cases where you explicitly need an 8-bit bit-pattern (like for networking protocols or binary file formats). It isn't intended for "small numbers." Moving between signed and unsigned numbers and different sized-numbers are common sources of bugs, and is intentionally made cumbersome.
If you do need to force a Double to be a whole number, just use Int rather than UInt8 in most cases. In most of these cases it looks like you really mean floor() rather than Int() anyway. You're just normalizing to an whole number.
That said, a more typical way to do your formatting is:
import Foundation
let totalSeconds: NSTimeInterval = 100.51
let frac = Int((totalSeconds - floor(totalSeconds)) * 100)
let seconds = Int(totalSeconds % 60)
let minutes = Int((totalSeconds / 60) % 60)
let result = String(format: "%02d:%02d:%02d", minutes, seconds, frac)
This line:
let adjustedTime = UInt8(timepenalty + elapsedTime)
is attempting to add a UInt8 (time penalty) and an NSTimeInterval (double, elapsedTime) which fails as there is no implicit type conversion in Swift. Change it to:
let adjustedTime = timepenalty + UInt8(elapsedTime)
Which converts the NSTimeInterval to a UInt8 before the addition.
UInt8 and NSTimeInterval are two different types. You need to make each operand the same type. (Or you could use operator overloading.)
I found the answer to this, but unfortunately it's using Java. I have two times, formatted as HHmm (no colons). I need to figure out how many 15 minute time segments are in the difference. For example, I have a start time of 1000 and an end time of 1130 (military time).
When I subtract the two dates, I get 130, which is meaningless for computations.
Is there an existing method that will do this for me? (I have spent the last 6 hours trying SO and Google, but found nothing).
UPDATE: I would appreciate it if whoever downvoted me please reverse it. The question is very pertinent and others will find it useful. Thank you.
Parse each time and convert to minutes. So 1000 becomes 10 hours 0 minutes for a total of 600 minutes. 1130 becomes 11 hours 30 minutes for a total of 690 minutes. Subtract the two values for a difference of 90 minutes. Now divide by 15 to get 6.
The following assumes all times are 4 digit military times:
NSString *startTime = #"1000";
NSString *endTime = #"1130";
int startMinues = [[startTime substringToIndex:2] intValue] * 60 + [[startTime substringFromIndex:2] intValue];
int endMinues = [[endTime substringToIndex:2] intValue] * 60 + [[endTime substringFromIndex:2] intValue];
int minutes = endMinutes - startMinutes;
int units = minutes / 15;
This gives whole units of your 15 minute blocks.
Use -[NSCalendar components:fromDate:toDate:options], like this:
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalenderUnitMinute fromDate:startDate toDate:endDate options:0];
NSInteger numberOfMinutes = [components minute];
Once you have the number of minutes, it should just be a matter of dividing by 15 to get the number of 15 minute chunks.
Try using NSDateComponents:
NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDateComponents *components = [calendar components:NSMinuteCalendarUnit|NSHourCalendarUnit
fromDate:dateA
toDate:dateB
options:0];
int increments = components.hour*4 + components.minute/15;
Format is rather simple:
int HHmm = [date intValue];
int HH = HHmm / 100;
int mm = HHmm % 100;
Diff, for two parsed dates:
int diff = ((HH2 * 60 + mm2) - (HH1 * 60 + mm1)) / 15;
I have some issue when calculating 3 CGFloats
I have: -34.522 + 39.049 + 0.2889 = ios gives me 73
but it should give me more like aproximative to an normal calculator values like = 4.81
CGFloat x = (46.2076 * -34.522) + (60.3827 * 39.049) + (2.028 * 0.2889);
NSLog(#"d %f",x); ->> 763.291199
CGFloat t = -34.522 + 39.049 + 0.2889;
NSLog(#"%f",t);
I'm not 100% sure if this is what you're asking, but if you only want 2 digits of precision, you have to specify this. It's easy to do via format specifier by using %.2f where 2 is the number of digits after the decimal place to be shown.
CGFloat x = (46.2076 * -34.522) + (60.3827 * 39.049) + (2.028 * 0.2889);
NSLog(#"d %.2f",x);
Alternatively, this can also be done with NSNumberFormatter.
NSNumberFormatter *formatter = [NSNumberFormatter new];
[formatter setPositiveFormat:#"#.##"];
NSString *output = [formatter stringFromNumber:#(x)];
NSLog(#"Out: %#",output);
I am trying to make an approximation of the length of day from sunrise to sunset, and the length of night from sunset to sunrise. My present approximation is crude (it assumes yesterday and tomorrow have equivalent values to today), but for now I am not specifically concerned with pinpointing yesterday sunset, today sunrise, today sunset, and tomorrow sunrise (yet). My goal is a calculation based on twelve equal hours per night (twelve equal to each other, not equal to a standard hour or daytime hour), and twelve equal hours per day.
What I am concerned with is that in my iOS app, the calculation is way off; a minute flies by in 5-6 (standard) seconds' time. When I use unmodified time, in other code from here, the clock moves at a standard pace, but when I try to get this code to feed the clock code, something is out of bounds.
The code I've been working on, as an approximation, is:
NSDate *now = [[NSDate alloc] init];
NSDate *factory = [[NSDate alloc] init];
NSDate *summerSolstice2013 = [factory initWithTimeIntervalSinceReferenceDate:_referenceSummerSolstice];
double distanceAlong = [now timeIntervalSinceDate:summerSolstice2013];
double angleAlong = M_PI * 2 * distanceAlong / (2 * (_referenceWinterSolstice - _referenceSummerSolstice));
double currentHeight = cos(angleAlong) * _latitudeAngle + _tiltAngle;
...
if (_secondsAreNatural)
{
_secondsAreShadowed = FALSE;
double dayDuration = 12 * 60 * 60 + 12 * 60 * 60 * sin(currentHeight);
double midday = fmod(24 * 60 * 60 * _longitudeAngle / (2 * M_PI) + 12 * 60 * 60, 24 * 60 * 60);
double sunrise = midday - dayDuration / 2;
double sunset = midday + dayDuration / 2;
double seconds = fmod([now timeIntervalSinceReferenceDate], 24 * 60 * 60);
double proportionAlong = 0;
if (seconds < sunrise)
{
_naturalSeconds = (seconds - sunset - 24 * 60 * 60) / (sunrise - sunset - 24 * 60 * 60);
}
else if (seconds > sunset)
{
_naturalSeconds = 12 * 60 * 60 * (seconds - sunset) / (sunrise + 24 * 60 * 60 - sunset) + 18 * 60 * 60;
}
else
{
_naturalSeconds = 12 * 60 * 60 * (seconds - sunrise) / (sunset - sunrise) + 6 * 60 * 60;
}
}
Are there any problems (given that this approximation can probably be refined to any extent) you can pinpoint in this code?
Thanks,
--EDIT--
The code I wrote above was fairly demanding in terms of the loose ends presented to someone reading it. I tried to take another pass, and rewrite it in simpler terms and with a purer mathematical model. I wrote, comments added:
NSDate *now = [[NSDate alloc] init];
NSDate *summerSolstice2013 = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate:_referenceSummerSolstice];
double distanceAlong = [now timeIntervalSinceDate:summerSolstice2013];
// How far along are we, in seconds, since the reference date?
double angleAlong = M_PI * 2 * distanceAlong / (2 * (_referenceWinterSolstice - _referenceSummerSolstice));
// What's the angle if 2 π radians corresponds to a whole year?
double currentHeight = cos(angleAlong) * _latitudeAngle + _tiltAngle;
// _latitudeAngle is the angle represented by our latitude; _tiltAngle is the angle of the earth's tilt.
NSInteger day = 24 * 60 * 60;
// 'day' could have been called secondsInADay, but it was mean to reduce the number of multiplicands represented in the code.
// If we are in the endless day or endless night around the poles, leave the user with standard clock hours.
if (currentHeight > M_PI / 2)
{
_secondsAreShadowed = TRUE;
}
else if (currentHeight < - M_PI / 2)
{
_secondsAreShadowed = TRUE;
}
// Otherwise, calculate the time this routine is meant to calculate. (This is the main intended use case.)
else if (_secondsAreNatural)
{
_secondsAreShadowed = FALSE;
// closestDay is intended to be the nearest midnight (or, in another hemisphere, midday), not exactly in hours offset from UTC, but in longitude offset from Greenwich.
double closestDay;
if (fmod(distanceAlong, day) < .5 * day)
{
closestDay = distanceAlong - fmod(distanceAlong, day);
}
else
{
closestDay = day + distanceAlong - fmod(distanceAlong, day);
}
// As we go through the calculations, for the most part we keep up information on the previous and next days, which will to some degree be consulted at the end.
double previousDay = closestDay - day;
double nextDay = closestDay + day;
// For the three days, what proportion of the way along are they from the solstices?
double closestDayAngleAlong = M_PI * 2 * closestDay / (2 * (_referenceWinterSolstice - _referenceSummerSolstice));
double previousDayAngleAlong = M_PI * 2 * previousDay / (2 * (_referenceWinterSolstice - _referenceSummerSolstice));
double nextDayAngleAlong = M_PI * 2 * nextDay / (2 * (_referenceSummerSolstice - _referenceSummerSolstice));
// What angle are we placed by on the year's cycle, between _latitudeAngle + _tiltAngle and -latitudeAngle + _tiltAngle?
double closestDayHeight = cos(closestDayAngleAlong) * _latitudeAngle + _tiltAngle;
double previousDayHeight = cos(previousDayAngleAlong) * _latitudeAngle + _tiltAngle;
double nextDayHeight = cos(nextDayAngleAlong) * _latitudeAngle + _tiltAngle;
// Based on that, what are the daylight durations for the three twenty-four hour days?
double closestDayDuration = day / 2 + (day / 2) * sin(closestDayHeight);
double previousDayDuration = day / 2 + (day / 2) * sin(previousDayHeight);
double nextDayDuration = day / 2 + (day / 2) * sin(nextDayHeight);
// Here we use both morning and evening for the closest day, and the previous day's morning and the next day's evening.
double closestDayMorning = closestDay + (day / 2) - (closestDayDuration / 2);
double closestDayEvening = closestDay + (day / 2) + (closestDayDuration / 2);
double previousDayEvening = previousDay + (day / 2) + (previousDayDuration / 2);
double nextDayMorning = nextDay + (day / 2) + (nextDayDuration / 2);
// We calculate the proportion along the day that we are between evening and morning (or morning and evening), along with the sooner endpoint of that interval.
double proportion;
double referenceTime;
if (distanceAlong < closestDayMorning)
{
proportion = (distanceAlong - previousDayEvening) / (closestDayMorning - previousDayEvening);
referenceTime = previousDay + day * 3 / 4;
}
else if (distanceAlong > closestDayEvening)
{
proportion = (distanceAlong - closestDayEvening) / (nextDayMorning - closestDayEvening);
referenceTime = closestDay + day * 3 / 4;
}
else
{
proportion = (distanceAlong - closestDayMorning) / (closestDayEvening - closestDayMorning);
referenceTime = closestDay + day * 1 / 4;
}
// Lastly, we take both that endpoint and the proportion of it, and we get the number of seconds according to the daylight / nighttime calculation intended.
_naturalSeconds = referenceTime + proportion * day / 2;
I was hoping to make the code clearer and easier to grasp, and I think I did that, but it is displaying similar behavior to my previous attempt: the clock hands spin by at about ten times natural time when they should be within a factor of .8 to 1.2 of standard hours/minutes/seconds.
Any advice? Has my edited code been any clearer either about what is intended or what is wrong?
Thanks,
Your code is hard to follow, but I'll try to get you some tips:
There are existing libraries out there that compute solar angle/azimuth and sunrise/sunset for a given date. Use google as a help, here's some relevant resources: http://www.esrl.noaa.gov/gmd/grad/solcalc/ If you don't find any useful source code, I could post some.
Do not use double to calculate with dates and times. That's confusing and results in errors. Use a data type that is intended to store dates.
For your code, you say that the time is running to fast. Since referenceTime and day in the last line are constant (at least for half a day), the error must be in proportion. I think you're mixing to many cases there. The interpolation should go from the start of the range to the end, so in the case
proportion = (distanceAlong - previousDayEvening) / (closestDayMorning - previousDayEvening);
referenceTime = previousDay + day * 3 / 4;
proportion should run from (previousDay + day * 3 / 4) to (closestDay + day * 3 / 4), or, described differently, from the dusk to dawn of closestDay. But it's completely unclear how this interpolation should work.
Try to draw a diagram of the different cases (I believe there should only be two, one for day and one for night) and the corresponding interpolation.
But: What are you trying to achieve after all? The resulting time is just a forward running time, it is actually independent of latitude or longitude or time of day. So to make the time run, you don't need to know where the sun is.