I would like to report to an user the current progress about a background counter, however, I'm stuck in my method.
Indeed, I want more the counter timeout is higher and more there will be information.
For example, if the user sets a counter with a timeout of 60 secs, the counter will display at 30secs the remaining time, but if the user sets a counter with a one day timeout, the counter will display approximately every hour the remaining time.
So I did this, but I think it could largely be optimized with an exponential way..
Could you help me please
Here's my code:
TimeSpan time = TimeSpan.FromSeconds(Seconds - i);
string strTime;
if (Seconds > 30 && Seconds <= 300)
{
if (i == Seconds / 2)
{
strTime = time.ToString(#"mm\:ss");
account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
}
}
else if (Seconds > 300 && Seconds <= 1800)
{
int firstOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds / 3));
int secondOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (2/3)));
if (i == firstOcc || i == secondOcc || i == Seconds - 60)
{
strTime = time.ToString(#"mm\:ss");
account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
}
}
else if (Seconds > 1800 && Seconds <= 7200)
{
int firstOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds / 5));
int secondOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (2 / 5)));
int thirdOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (3 / 5)));
int fourthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (4 / 5)));
if (i == firstOcc || i == secondOcc || i == thirdOcc || i == fourthOcc || i == Seconds - 60)
{
strTime = time.ToString(#"H\:mm\:ss");
account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
}
}
else if (Seconds > 7200 && Seconds <= 43200)
{
int firstOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds / 8));
int secondOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (2 / 8)));
int thirdOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (3 / 8)));
int fourthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (4 / 8)));
int fifthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (5 / 8)));
int sixthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (6 / 8)));
int seventhOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (7 / 8)));
if (i == firstOcc || i == secondOcc || i == thirdOcc || i == fourthOcc || i == fifthOcc || i == sixthOcc || i == seventhOcc || i == Seconds - 60)
{
strTime = time.ToString(#"H\:mm\:ss");
account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
}
}
else if (Seconds > 43200)
{
Which is very redundant
I would use the log base 2. So the timers would be 32 seconds, 64 seconds, 128 seconds, 256 seconds, 512 seconds, 1024 seconds, 2048 seconds. So code would look something like this :
List<int> seconds = new List<int>() { 60, 200, 400, 600, 800, 2300, 3599 };
foreach (int second in seconds)
{
int timer = (second < 64)? 32 : (int)Math.Pow(2,(int)Math.Log(second, 2));
Console.WriteLine("Seconds : '{0}'; Timer : '{1}'", second, timer);
}
Console.ReadLine();
Here is an (untested) example of how you might go about refactoring your code to prevent repetition.
var time = TimeSpan.FromSeconds(seconds - i);
if (seconds <= 30)
{
// What to do here?
return;
}
int factor;
string format;
if (seconds <= 300)
{
factor = 2;
format = #"mm\:ss";
}
else if (seconds <= 1800)
{
factor = 3;
format = #"mm\:ss";
}
else if (seconds <= 7200)
{
factor = 5;
format = #"H\:mm\:ss";
}
else if (seconds <= 43200)
{
factor = 8;
format = #"H\:mm\:ss";
}
else
{
// Defaults when no other condition is met.
factor = 10;
format = #"H\:mm\:ss";
}
if (i == seconds - 60 || Enumerable.Range(1, factor - 1).Any(n => i == seconds / factor * n))
{
string timeDisplay = time.ToString(format);
account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", timeDisplay));
}
Related
I can't figure out why I keep getting the "Index was outside the
bounds of the array" error. I am trying to tally up the salaries to
display.
Is there are any someone who could explain to me how the error message works.
namespace sales_commission {
class Program {
static void Main (string[] args) {
const int ARRAY_LENGTH = 8;
int[] salaries = { 210, 400, 450, 950, 800, 330, 430, 233, 223, 590, 679, 1000 };
var salary = new int[ARRAY_LENGTH];
foreach(int number in salaries) {
try {
if (number >= 200 && number <= 299) {
salary[0]++;
} else if (number >= 300 && number <= 399) {
salary[1]++;
} else if (number >= 400 && number <= 499) {
salary[2]++;
} else if (number >= 500 && number <= 599) {
salary[3]++;
} else if (number >= 600 && number <= 699) {
salary[4]++;
} else if (number >= 700 && number <= 799) {
salary[5]++;
} else if (number >= 800 && number <= 899) {
salary[6]++;
} else if (number >= 900 && number <= 999) {
salary[7]++;
} else if (number >= 1000) {
salary[8]++;
}
} catch (IndexOutOfRangeException ex) {
Console.WriteLine (ex.Message);
Console.WriteLine ($"salaries[{number}] = {salary[number]}");
}
}
for (var result = 0; result <= salary.Length; ++result) {
Console.WriteLine ($"{result* 100 + 200} - {result * 100 + 200 + 99} {salary[result],15}");
}
}
}
}
You have 9 salary brackets. 200-299, 300-399, 400-499, 500-599, 600-699, 700-799, 800-899, 900-999 and >= 1000. That means you need 9 storage spaces for the counts. Array indexes start at 0, so your array length needs to be 9, this gives you [0 to 8] indexes.
const int ARRAY_LENGTH = 8; // This needs to be 9.
You get an array out of bounds because:
} else if (number >= 1000) {
salary[8]++; // Index 8 doesn't exist, only [0 to 7] for an ARRAY_LENGTH of 8.
Your loop also accesses data outside of the array bounds. This is because the condition of your loop runs until it reaches and includes the index of the length itself. So if your array has 8 spaces [0 to 7], your loop runs from [0 to 8] and the moment it access index 8, you're out of bounds. This can easily be fixed as below:-
for (var result = 0; result <= salary.Length; ++result) { // Change this to result < salary.Length
Console.WriteLine ($"{result* 100 + 200} - {result * 100 + 200 + 99 {salary[result],15}");
}
I've calculated a stepsize for an axis on a chart.
Also I have the Min and Max -Values. Now I need to calculate all ticks so that all values between my Min and Max can be displayed.
For Example:
Stepsize: 1000
Min: 213
Max: 4405
Expected ticks: 0,1000,2000,3000,4000,5000
Stepsize: 500
Min: -1213
Max: 1405
Expected ticks: -1500,-1000,-500,0,500,1000,1500
Until now I'm trying to calculate the first value with "try and error" like:
bool firstStepSet = false;
double firstStep = stepSize;
do
{
if (xValue >= (firstStep - (stepSize / 2)) && xValue <=
(firstStep + (stepSize / 2)))
{
firstStepSet = true;
this.myBarXValues.Add(firstStep, 0);
}
else if (xValue > stepSize)
{
firstStep += stepSize;
}
else
{
firstStep -= stepSize;
}
}
while (!firstStepSet);
And after that I'm adding steps to this list until all values fit.
This seems pretty dirty to me and I want to know if there is another solution.
So what I need is a solution which calculate the first tick that I need.
This function calculates first and last step values:
static void CalcSteps(int min, int max, int stepSize, out int firstStep, out int lastStep)
{
if (min >= 0)
{
firstStep = (min / stepSize) * stepSize;
}
else
{
firstStep = ((min - stepSize + 1) / stepSize) * stepSize;
}
if (max >= 0)
{
lastStep = ((max + stepSize - 1) / stepSize) * stepSize;
}
else
{
lastStep = (max / stepSize) * stepSize;
}
}
You can calculate axis limits using integer rounding to lower and higher values
low = stepsize * (min / stepsize) //integer division needed
high = stepsize * ((max + stepsize - 1) / stepsize)
Example Python code returns limits and number of ticks (one more than interval count)
def getminmax(minn, maxx, step):
low = (minn // step)
high = (maxx + step - 1) // step
ticks = high - low + 1
return low * step, high * step, ticks
print(getminmax(213, 4405, 1000))
print(getminmax(-1213,1405, 500))
(0, 5000, 6)
(-1500, 1500, 7)
int marsHeight = ml.getHeight() / 100 * 100; // measure by 100s despite height value
int chartHeight = (marsHeight >= 1000) ? marsHeight : 1000;
for (int i = 0; i <= (chartHeight / 100); i++)
{
if (i == 0)
{
Console.WriteLine("{0}m: \t*", (marsHeight - (i * 100))); // in order to print in descending order: (height - (i * 100)
continue;
}
Console.WriteLine("{0}m:", (marsHeight - (i * 100)));
}
I want my program to print out this if marsHeight is greater than 1000 (and it currently does):
[marsHeight]m:
[marsHeight - 100]m:
...
1000m:
900m:
800m:
...
0m: // this works perfectly!
Currently if marsHeight is less than 1000 (like 990)the program prints out:
900m: *
800m:
...
0m:
-100m:
What I want is this if it's less than 1000m:
1000m:
900m: *
800m:
...
0m:
I'm new to programming. Where am I going wrong with my logic?
Change this
int chartHeight = (marsHeight >= 1000) ? marsHeight : 1000;
to
int chartHeight = (marsHeight <= 1000) ? marsHeight : 1000;
^
and if you want the output of to be same in both the condition like if it greater or smaller. You can make it like Not Equal to Like
int chartHeight = (marsHeight =! 1000) ? marsHeight : 1000;
^^
// First get the value.
int height = ml.getHeight();
// Now round to nearest even value.
int chartHeight = height / 100 * 100;
// Find initial value of cycle.
int forStart;
if (chartHeight > 1000)
forStart = chartHeight;
else
forStart = chartHeight < 0 ? 0 : 1000;
// Also you can simplify cycle.
for (int i = forStart; i >= 0; i -= 100)
if(i==chartHeight)
Console.WriteLine("{0}m:*", i);
else
Console.WriteLine("{0}m:", i);
The output will be:
if height 990
1000m
900m*
...
0m
if height >1000
1100m*
1000m
...
0m
if height 540
1000m
...
500m*
...
0m
I'm porting some calculations from Excel to C# which use the Days360 function (the default/US method). Using the Wikipedia page as a guide, I came up with this code:
public static int Days360(DateTime a, DateTime b)
{
var dayA = a.Day;
var dayB = b.Day;
if (IsLastDayOfFebruary(a) && IsLastDayOfFebruary(b))
dayB = 30;
if (dayA == 31 || IsLastDayOfFebruary(a))
dayA = 30;
if (dayA == 30 && dayB == 31)
dayB = 30;
return ((b.Year - a.Year) * 12 + b.Month - a.Month) * 30 + dayB - dayA;
}
private static bool IsLastDayOfFebruary(DateTime date)
{
if (date.Month != 2)
return false;
int lastDay = DateTime.DaysInMonth(date.Year, 2);
return date.Day == lastDay;
}
I tested it with a (small) range of inputs and the results mostly agree with Excel's native function except if I use 2015-02-28 for both a and b. My code returns 0 and Excel -2.
My result seems more reasonable but at this point, I'd prefer to calculate the exact same result as Excel. There might be other inputs where they disagree so I don't want to make a special case just for that date.
Does anyone know the exact algorithm that Excel uses?
EDIT: There was a glaring bug in the original code I posted which is unrelated to the question. I had already fixed that one but I copied from the wrong file when posting the question.
According to this Wikipedia article the Microsoft Excel Days360 function is equivalent to 30/360 BMA/PSA. So to get exact results as MS Excel we need to implement the BMA/PSA method. I have implemented the method.
private double Days360(DateTime StartDate, DateTime EndDate)
{
int StartDay = StartDate.Day;
int StartMonth = StartDate.Month;
int StartYear = StartDate.Year;
int EndDay = EndDate.Day;
int EndMonth = EndDate.Month;
int EndYear = EndDate.Year;
if (StartDay == 31 || IsLastDayOfFebruary(StartDate))
{
StartDay = 30;
}
if (StartDay == 30 && EndDay == 31)
{
EndDay = 30;
}
return ((EndYear - StartYear) * 360) + ((EndMonth - StartMonth) * 30) + (EndDay - StartDay);
}
private bool IsLastDayOfFebruary(DateTime date)
{
return date.Month == 2 && date.Day == DateTime.DaysInMonth(date.Year, date.Month);
}
I had the same need, I found the solution in the function on line 51 of this phpexcel library
dateDiff360
this is part of the class code for the calculation
/**
* Identify if a year is a leap year or not
*
* #param integer $year The year to test
* #return boolean TRUE if the year is a leap year, otherwise FALSE
*/
public static function isLeapYear($year)
{
return ((($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0));
}
/**
* Return the number of days between two dates based on a 360 day calendar
*
* #param integer $startDay Day of month of the start date
* #param integer $startMonth Month of the start date
* #param integer $startYear Year of the start date
* #param integer $endDay Day of month of the start date
* #param integer $endMonth Month of the start date
* #param integer $endYear Year of the start date
* #param boolean $methodUS Whether to use the US method or the European method of calculation
* #return integer Number of days between the start date and the end date
*/
private static function dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, $methodUS)
{
if ($startDay == 31) {
--$startDay;
} elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !self::isLeapYear($startYear))))) {
$startDay = 30;
}
if ($endDay == 31) {
if ($methodUS && $startDay != 30) {
$endDay = 1;
if ($endMonth == 12) {
++$endYear;
$endMonth = 1;
} else {
++$endMonth;
}
} else {
$endDay = 30;
}
}
return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360;
}
This algorithm also include the optional parameter method:
int startMonthDays = 0;
int endMonthDays = 0;
double diff = 0;
if(method.Equals("TRUE"))
{
if(dtStartDate.getDay() < 30)
{
startMonthDays = (30 - dtStartDate.getDay());
}
else
{
startMonthDays = 0;
}
if(dtEndDate.getDay() < 30)
{
endMonthDays = dtEndDate.getDay();
}
else
{
endMonthDays = 30;
}
diff = (dtEndDate.getYear() - dtStartDate.getYear())*360 +
(dtEndDate.getMonth() - dtStartDate.getMonth() - 1)*30 +
startMonthDays + endMonthDays;
}
else
{
if(DateCalendar.daysInMonth(dtStartDate.getYear(), dtStartDate.getMonth()) == dtStartDate.getDay())
{
startMonthDays = 0;
}
else
{
startMonthDays = (30 - dtStartDate.getDay());
}
if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) == dtEndDate.getDay())
{
if(dtStartDate.getDay() < DateCalendar.daysInMonth(dtStartDate.getYear(), dtStartDate.getMonth()) - 1)
{
if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) > 30)
{
endMonthDays = DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth());
}
else
{
endMonthDays = dtEndDate.getDay();
}
}
else
{
if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) > 30)
{
endMonthDays = DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) - 1;
}
else
{
endMonthDays = dtEndDate.getDay();
}
}
}
else
{
endMonthDays = dtEndDate.getDay();
}
diff = (dtEndDate.getYear() - dtStartDate.getYear())*360 +
(dtEndDate.getMonth() - dtStartDate.getMonth() - 1)*30 +
startMonthDays + endMonthDays;
}
with
public static int daysInMonth (int year, int month)
{
if (DateTime.IsLeapYear(year) && month == 2)
{
return 29;
}
else
{
return table[month - 1];
}
}
and
private static readonly int[] table = new int[]{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Test the next
public static int Days360(DateTime a, DateTime b)
{
var dayA = a.Day;
var dayB = b.Day;
if (IsLastDayOfMonth(a) && IsLastDayOfMonth(b)) {
dayB = Math.min(30, dayB);
} else if (dayA == 30 && dayB ==31) {
DayB = 30;
}
if (IsLastDayOfMonth(a))
dayA = 30;
return ((b.Year - a.Year) * 360 + b.Month - a.Month) * 30 + dayB - dayA;
}
private static bool IsLastDayOfMonth(DateTime date)
{
int lastDay = DateTime.DaysInMonth(date.Year, date.Month);
return date.Day == lastDay;
}
Is there a free library or class for formatting a date in a pretty way such as "5 minutes ago" or "yesterday"?
I'd be satisfied with the same code in another language that I could port to Actionscript (like Java or C#)
would this help? Should be very easy to port to AS3.
/*
* JavaScript Pretty Date
* Copyright (c) 2008 John Resig (jquery.com)
* Licensed under the MIT license.
*/
// Takes an ISO time and returns a string representing how
// long ago the date represents.
function prettyDate(time){
var date = new Date((time || "").replace(/-/g,"/").replace(/[TZ]/g," ")),
diff = (((new Date()).getTime() - date.getTime()) / 1000),
day_diff = Math.floor(diff / 86400);
if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 )
return;
return day_diff == 0 && (
diff < 60 && "just now" ||
diff < 120 && "1 minute ago" ||
diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||
diff < 7200 && "1 hour ago" ||
diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||
day_diff == 1 && "Yesterday" ||
day_diff < 7 && day_diff + " days ago" ||
day_diff < 31 && Math.ceil( day_diff / 7 ) + " weeks ago";
}
// If jQuery is included in the page, adds a jQuery plugin to handle it as well
if ( typeof jQuery != "undefined" )
jQuery.fn.prettyDate = function(){
return this.each(function(){
var date = prettyDate(this.title);
if ( date )
jQuery(this).text( date );
});
};
I'm using this Relative Time code for a Twitter widget I'm working on. It's PHP, but nothing feature-specific so a port should be pretty easy.
I ended up writing my own.
/**
* Takes a Date object and returns a string in the format
* "X UNITS ago" where X is a number and UNITS is a unit of
* time. Also has some other strings like "yesterday".
*
* #author Mims Wright (with thanks to John Resig)
*
* #param date The date to convert to a past string.
* #param now Optional time to compare against. Default will be the present.
*/
public function getTimeElapsedString(date:Date, now:Date = null):String {
const SEC_PER_MINUTE:int = 60;
const SEC_PER_HOUR:int = SEC_PER_MINUTE * 60;
const SEC_PER_DAY:int = SEC_PER_HOUR * 24;
const SEC_PER_WEEK:int = SEC_PER_DAY * 7;
const SEC_PER_MONTH:int = SEC_PER_DAY * 30;
const SEC_PER_YEAR:int = SEC_PER_MONTH * 12;
// if now isn't defined, make it a new Date object (the present)
if (!now) { now = new Date(); }
// don't use secondsElapsed here because the values are
// huge so they use uints and are never negative
if (now.time < date.time) { return "in the future"; }
// get the difference in seconds between the two values.
var secondsElapsed:uint = Math.floor((now.time - date.time) / 1000);
// seconds
if (secondsElapsed < SEC_PER_MINUTE) { return "just now"; }
// minutes
if (secondsElapsed < SEC_PER_HOUR) {
var minutes:int = int(secondsElapsed / SEC_PER_MINUTE);
return formatAgoString(minutes, "minute");
}
// hours
if (secondsElapsed < SEC_PER_DAY) {
var hours:int = int(secondsElapsed / SEC_PER_HOUR);
return formatAgoString(hours, "hour");
}
// days
if (secondsElapsed < SEC_PER_WEEK) {
var days:int = int(secondsElapsed / SEC_PER_DAY);
if (days == 1) { return "yesterday"; }
return formatAgoString(days, "day");
}
// weeks
if (secondsElapsed < SEC_PER_MONTH) {
var weeks:int = int(secondsElapsed / SEC_PER_WEEK);
return formatAgoString(weeks, "week");
}
// months
if (secondsElapsed < SEC_PER_YEAR) {
var months:int = int(secondsElapsed / SEC_PER_MONTH);
return formatAgoString(months, "month");
}
// years
return "more than a year ago";
// Returns a string in the format "count unit(s) ago"
function formatAgoString(count:int, unit:String):String {
return count + " " + unit + (count > 1 ? "s" : "") + " ago";
}
}
Going to try PrettyTime (github) in Java now. Multi-language and customizable.