ক্যালেন্ডার অ্যাপ্লিকেশনটিতে পুনরাবৃত্তি ইভেন্টগুলির মডেল করার সর্বোত্তম উপায় কী?


224

আমি একটি গ্রুপ ক্যালেন্ডার অ্যাপ্লিকেশন তৈরি করছি যা পুনরাবৃত্ত ইভেন্টগুলিকে সমর্থন করা প্রয়োজন, তবে এই ইভেন্টগুলি পরিচালনা করতে আমি যে সমস্ত সমাধান নিয়ে এসেছি তা হ্যাকের মতো মনে হয়। আমি কতদূর এগিয়ে যেতে পারি তা সীমাবদ্ধ করতে পারি এবং তারপরে একবারে সমস্ত ইভেন্ট তৈরি করতে পারি। অথবা আমি ইভেন্টগুলি পুনরাবৃত্তি হিসাবে সংরক্ষণ করতে পারি এবং ক্যালেন্ডারে যখন কেউ এগিয়ে দেখায় তখন এগুলিকে গতিশীলভাবে প্রদর্শন করতে পারি, তবে কেউ ইভেন্টের নির্দিষ্ট উদাহরণে বিশদ পরিবর্তন করতে চাইলে আমি সেগুলিকে একটি সাধারণ ইভেন্টে রূপান্তর করতে হবে।

আমি নিশ্চিত যে এটি করার আরও ভাল উপায় আছে তবে আমি এটি এখনও পাইনি। পুনরাবৃত্ত ইভেন্টগুলির মডেল করার সর্বোত্তম উপায় কী, যেখানে আপনি নির্দিষ্ট ইভেন্টের বিবরণ পরিবর্তন করতে বা মুছতে পারেন?

(আমি রুবি ব্যবহার করছি, তবে দয়া করে আপনার উত্তরটি সীমাবদ্ধ রাখবেন না Rub তবে কোনও রুবি-নির্দিষ্ট গ্রন্থাগার বা কিছু আছে তবে এটি জানা ভাল))

উত্তর:


93

আমি ভবিষ্যতের সমস্ত পুনরাবৃত্ত ইভেন্টগুলির জন্য একটি 'লিঙ্ক' ধারণাটি ব্যবহার করব। এগুলি গতিযুক্ত ক্যালেন্ডারে প্রদর্শিত হয় এবং একটি একক রেফারেন্স অবজেক্টে ফিরে লিঙ্ক করে। ইভেন্টগুলি সংঘটিত হওয়ার পরে লিঙ্কটি নষ্ট হয়ে যায় এবং ঘটনাটি একক উদাহরণ হয়ে যায়। যদি আপনি কোনও পুনরাবৃত্ত ইভেন্ট সম্পাদনা করার চেষ্টা করেন তবে ভবিষ্যতের সমস্ত আইটেম (যেমন একক লিঙ্কযুক্ত রেফারেন্স পরিবর্তন করুন) পরিবর্তন করতে অনুরোধ করুন বা কেবলমাত্র সেই দৃষ্টান্তটি পরিবর্তন করুন (এক্ষেত্রে এটিকে একক ক্ষেত্রে রূপান্তর করুন এবং তারপরে পরিবর্তন আনুন) change পরের কেসটি সামান্য সমস্যাযুক্ত কারণ আপনার ভবিষ্যতের সমস্ত ইভেন্টের পুনরাবৃত্ত তালিকায় ট্র্যাক রাখতে হবে যা একক দৃষ্টান্তে রূপান্তরিত হয়েছিল। তবে, এটি সম্পূর্ণরূপে সক্ষম।

সুতরাং, সংক্ষেপে, 2 শ্রেণির ইভেন্ট রয়েছে - একক দৃষ্টান্ত এবং পুনরাবৃত্ত ইভেন্ট।


ঘটনাগুলি সংযুক্ত হওয়ার পরে এবং ঘটনাগুলিকে এককভাবে রূপান্তর করার বিষয়ে আপনার ধারণাটি পছন্দ করুন। দুটি প্রশ্ন: - কেন এগুলি এককভাবে স্থির দৃষ্টান্তগুলিতে রূপান্তর করুন? কেন তাদের পুরোপুরি গতিশীল রাখবেন না? - আপনি প্রস্তাবিত লিঙ্ক ধারণার জন্য রেফারেন্স ভাগ করে নিতে পারেন! আগাম ধন্যবাদ!
rtindru

ইভেন্টগুলিকে এককভাবে রূপান্তর করার জন্য আমি যে ব্যবহারের ঘটনাটি পেয়েছি তা @rtindru হ'ল আপনি যখন আপনার ডাটাবেসে অন্যান্য মডেলের সাথে ইভেন্টের মডেলটি ব্যবহার করতে পারেন । উদাহরণস্বরূপ কোনও ইভেন্টের উপস্থিতি যাচাই করার জন্য, আপনি ব্যবহারকারীদের একটি আসল ইভেন্টের সাথে সংযুক্ত করতে চাইবেন (যা ঘটবে) happen
ক্লিনটন ইয়েবোাহ

60

মার্টিন ফওলার - ক্যালেন্ডারগুলির জন্য পুনরাবৃত্ত ইভেন্টগুলিতে কিছু আকর্ষণীয় অন্তর্দৃষ্টি এবং নিদর্শন রয়েছে।

ছোটজাতির বলদ মণি এই প্যাটার্নটি প্রয়োগ করে।


কিছু আরও ভাল কোড উদাহরণ ভাল হবে, যে কেউ বাস্তবায়িত একটি প্রকল্প জানেন?
টেদেউ মিয়া

33

পুনরাবৃত্ত ইভেন্টগুলির সাথে অনেকগুলি সমস্যা থাকতে পারে, আমার জানা কিছুগুলি হাইলাইট করুন।

সমাধান 1 - কোনও দৃষ্টান্ত নেই

আসল অ্যাপয়েন্টমেন্ট + পুনরাবৃত্ত তথ্য সংরক্ষণ করুন, সমস্ত দৃষ্টান্ত সংরক্ষণ করবেন না।

সমস্যা:

  • আপনার প্রয়োজন অনুসারে তারিখের উইন্ডোতে সমস্ত দৃষ্টান্ত গণনা করতে হবে cost
  • ব্যতিক্রমগুলি পরিচালনা করতে অক্ষম (যেমন আপনি কোনও একটি উদাহরণ মুছুন, বা সরান, বা বরং আপনি এই সমাধান সহ এটি করতে পারবেন না)

সমাধান 2 - স্টোর দৃষ্টান্ত

1 থেকে সমস্ত কিছু সঞ্চয় করুন, তবে সমস্ত দৃষ্টিকোণও মূল অ্যাপয়েন্টমেন্টের সাথে যুক্ত।

সমস্যা:

  • প্রচুর জায়গা নেয় (তবে স্থানটি সস্তা, তাই গৌণ)
  • ব্যতিক্রমগুলি অবশ্যই কৃপণভাবে পরিচালনা করতে হবে, বিশেষত যদি আপনি ফিরে যান এবং ব্যতিক্রম করার পরে মূল অ্যাপয়েন্টমেন্ট সম্পাদনা করেন। উদাহরণস্বরূপ, আপনি যদি তৃতীয় উদাহরণটি একদিন এগিয়ে যান, আপনি যদি ফিরে যান এবং মূল অ্যাপয়েন্টমেন্টের সময়টি সম্পাদনা করেন, তবে মূল দিনে অন্যটি পুনরায় -োকান এবং সরানোটি ছেড়ে চলে গেলে কী হবে? সরানো একটিকে লিঙ্কমুক্ত করবেন? সরানো একটি যথাযথভাবে পরিবর্তন করার চেষ্টা করবেন?

অবশ্যই, যদি আপনি ব্যাতিক্রম করতে যাচ্ছেন না, তবে সমাধানটি ঠিক হওয়া উচিত এবং আপনি মূলত সময় / স্থানের বাণিজ্য থেকে পছন্দ বেছে নিন।


36
আপনার যদি শেষের তারিখ না দিয়ে পুনরাবৃত্ত অ্যাপয়েন্টমেন্ট হয়? স্থান যতটা সস্তা, আপনার কাছে অসীম স্থান নেই, সুতরাং সলিউশন 2 সেখানে একটি অ-স্টার্টার হ'ল ...
শাল বেহর

13
সমাধান # 1 আসলে ব্যতিক্রমগুলি পরিচালনা করতে পারে। উদাহরণস্বরূপ, আরএফসি 5545 পরামর্শ দেয় যে সেগুলি সংরক্ষণাগার হিসাবে রয়েছে: ক) বাদ দেওয়া তারিখগুলির একটি তালিকা (যখন আপনি কোনও ঘটনা মুছবেন); খ) প্রোটোটাইপের রেফারেন্সের সাথে "বস্তুগত" ঘটনাগুলি (যখন আপনি কোনও ঘটনা সরিয়ে দেন)।
অ্যান্ডি মিখায়লেনকো

@ অ্যান্ডি, লাসের উত্তরে কিছু আকর্ষণীয় সংযোজন। তাদের চেষ্টা করে দেখুন।
জোনাথন উইলসন

1
@ শৈল: আমি মনে করি এটি একটি অ-স্টার্টার নয়। জন স্কিটি, যিনি এসও-তে বেশ সমাদৃত, মূলত একই প্রশ্নের উত্তরে উত্পন্ন উদাহরণগুলি সংরক্ষণের পরামর্শ দিয়েছেন: stackoverflow.com/a/10151804/155268
ব্যবহারকারী

1
@ ব্যবহারকারী - স্বীকৃত, আপনাকে ধন্যবাদ এটি এত অদ্ভুত - 4 বছর আগে আমি আমার মন্তব্য করেছি এবং তখন থেকে আমার সত্যিই এই সমস্যাটি মোকাবেলার দরকার হয়নি। গতকালই আমি একটি নতুন মডিউল ডিজাইনে প্রবেশ করলাম যাতে পুনরাবৃত্ত অ্যাপয়েন্টমেন্টগুলি জড়িত এবং আমি কীভাবে সেগুলি পরিচালনা করব তা ভাবছিলাম। এবং তারপরে - আমি আজ সকালে আপনার মন্তব্যের একটি এসও বিজ্ঞপ্তি পেয়েছি। মারাত্মকভাবে স্পোকি! কিন্তু আপনাকে ধন্যবাদ! :-)
শৈল বেহর

20

আমি একাধিক ক্যালেন্ডার-ভিত্তিক অ্যাপ্লিকেশনগুলি বিকাশ করেছি এবং পুনরায় ব্যবহারযোগ্য জাভাস্ক্রিপ্ট ক্যালেন্ডার উপাদানগুলির একটি সেটও রচনা করেছি যা পুনরাবৃত্তি সমর্থন করে। আমি পুনরাবৃত্তির জন্য কীভাবে ডিজাইন করব সে সম্পর্কে একটি সংক্ষিপ্ত বিবরণ লিখেছিলাম যা কারও পক্ষে সহায়ক হতে পারে। আমার লেখা লাইব্রেরির সাথে সুনির্দিষ্ট কয়েকটি বিট থাকা অবস্থায়, দেওয়া পরামর্শের সিংহভাগই কোনও ক্যালেন্ডার প্রয়োগের ক্ষেত্রে সাধারণ।

কিছু মূল বিষয়:

  • আইসিএআরআরএলআরএল ফর্ম্যাট ব্যবহার করে স্টোর পুনরাবৃত্তি - এটি এমন এক চাকা যা আপনি সত্যিই পুনর্নবীকরণ করতে চান না
  • আপনার ডাটাবেসে পৃথক পুনরাবৃত্ত ইভেন্টের দৃষ্টান্তগুলি সারি হিসাবে সংরক্ষণ করবেন না ! সর্বদা একটি পুনরাবৃত্তির ধরণ সংরক্ষণ করুন।
  • আপনার ইভেন্ট / ব্যতিক্রম স্কিমা ডিজাইনের অনেকগুলি উপায় রয়েছে তবে একটি প্রাথমিক শুরুর পয়েন্ট উদাহরণ সরবরাহ করা হয়
  • সমস্ত তারিখ / সময়ের মানগুলি ইউটিসিতে সংরক্ষণ করা উচিত এবং প্রদর্শনের জন্য স্থানীয় রূপান্তর করা উচিত
  • শেষ একটি পুনরাবৃত্ত ইভেন্ট জন্য সংরক্ষিত তারিখ সবসময় হওয়া উচিত পুনরাবৃত্তি সারির শেষ তারিখ (অথবা আপনার প্ল্যাটফর্মে এর "সর্বোচ্চ তারিখ" যদি "সব সময় প্রবেশ করুন" আবর্তক) এবং ইভেন্টের সময়কাল আলাদাভাবে সংরক্ষণ করা উচিত। এটি পরবর্তী ইভেন্টগুলির জন্য জিজ্ঞাসা করার এক বুদ্ধিমান উপায় নিশ্চিত করা।
  • ইভেন্টের উদাহরণ তৈরি এবং পুনরাবৃত্তির সম্পাদনার কৌশলগুলি ঘিরে কিছু আলোচনা অন্তর্ভুক্ত রয়েছে

এটি বাস্তবায়নের জন্য অনেকগুলি, অনেক বৈধ পদ্ধতির সাথে একটি সত্যই জটিল বিষয়। আমি বলব যে আমি সত্যিকারভাবে বেশ কয়েকবার পুনরাবৃত্তি সফলভাবে প্রয়োগ করেছি, এবং যে কেউ প্রকৃতপক্ষে এটি করেনি তার কাছ থেকে এই বিষয়ে পরামর্শ নেওয়ার বিষয়ে আমি সতর্ক থাকব।


ঘটনাগুলি ঘটে যখন পুনরাবৃত্তির ঘটনাগুলি ঘটে তাই আপনার ক্যালেন্ডারের ইতিহাসটি সঠিক হতে পারে সম্ভবত
রিচার্ড হাভেন

পুনঃটুইট ধারাবাহিকভাবে, অতীত, বর্তমান বা ভবিষ্যতের ভবিষ্যতে RRULE নিদর্শনগুলি থেকে আপনার সর্বদা উদাহরণ উত্পন্ন করা উচিত। Historicalতিহাসিক ঘটনাগুলির জন্য আলাদা কিছু করার কোনও কারণ থাকবে না। আপনার যুক্তি কেবল যেকোন স্বেচ্ছাসেবী তারিখের পরিসীমা বিরুদ্ধে আরআরইউএল মূল্যায়ন করা উচিত এবং ম্যাচের ইভেন্টের উদাহরণগুলি প্রত্যাবর্তন করবে।
ব্রায়ান মোসকাউ

@ ব্রায়ানমোসকাউ সুন্দর এবং সহায়ক ওভারভিউ!
প্রেজেক নওক

@ ব্রায়ানমোসকাউ কিন্তু এরপরে যখন কিছু ঘটনা ইতিমধ্যে ঘটেছে তার পরে কেউ আরআরইউএল সম্পাদনা করে তখন আপনার ক্যালেন্ডারের অতীতের দেখাগুলি সঠিক তথ্য প্রদর্শন করবে না? অথবা সম্ভবত সে ক্ষেত্রে আপনি আরআরইউএলকে "শাখা" দিয়েছিলেন এবং সত্যিকারের অতীত ঘটনাগুলির প্রতিনিধিত্ব করে RRULE নিদর্শনগুলির সংশোধিত সংস্করণগুলি রাখবেন?
খ্রিস্টান

1
@ ক্রিশ্চিয়ান যখন আপনি বেশিরভাগ ক্যালেন্ডারে পুনরাবৃত্তির নিয়ম আপডেট করেন, তখন তারা সাধারণত "সমস্ত ইভেন্ট সম্পাদনা করুন বা এটি কেবলমাত্র একটি ভবিষ্যত বা কেবল ভবিষ্যতে" ব্যবহারকারীদের আচরণ চয়ন করতে দেয়। বেশিরভাগ ক্ষেত্রে ব্যবহারকারীর সম্ভবত সম্ভবত "এটি এগিয়ে যাওয়ার পরিবর্তন করুন" তবে আবার আপনার সফ্টওয়্যারটি কীভাবে কাজ করে এবং ব্যবহারকারীকে কী বিকল্পগুলি দেয় তা সিদ্ধান্ত নেওয়া আপনার পক্ষে to
ব্রায়ান মোসকাউ

19

আপনি আইক্যালেন্ডার সফ্টওয়্যার বাস্তবায়ন বা মানক নিজেই ( আরএফসি 2445 আরএফসি 5545 ) দেখতে চাইতে পারেন। দ্রুত মনে আসা লোকেরা হ'ল মোজিলা প্রকল্পগুলি http://www.mozilla.org/projects/cocolate/ একটি দ্রুত অনুসন্ধানের মাধ্যমে http://icocolate.rubyforge.org/ প্রকাশিত হয় ।

আপনি কীভাবে ইভেন্টগুলি সঞ্চয় করতে চলেছেন তার উপর নির্ভর করে অন্যান্য বিকল্পগুলি বিবেচনা করা যেতে পারে। আপনি কি নিজের ডাটাবেস স্কিমা তৈরি করছেন? আইক্যালেন্ডার-ভিত্তিক কিছু ব্যবহার করছেন?


আপনি যদি এইগুলির মধ্যে একটিতে কেবল একটি লিঙ্ক সরবরাহ করতে পারেন তবে আপনার পোস্টটি সঠিক হবে
জিন

7
RFC2445 মত দেখায় RFC5545 (দ্বারা অপ্রচলিত তৈরি করা হয়েছে tools.ietf.org/html/rfc5545 )
এরিক Freese

16

আমি নিম্নলিখিত সঙ্গে কাজ করছি:

এবং অগ্রগতিতে থাকা একটি মণি যা ইনপুট টাইপের সাথে ফর্মটাস্টিককে প্রসারিত করে: পুনরাবৃত্তি ( form.schedule :as => :recurring), যা আবার আইকালের মতো ইন্টারফেস এবং ভিউটিকে আবার before_filterকোনও IceCubeঅবজেক্টে সিরিয়ালাইজ করার জন্য , ঘেটো-ল্য।

আমার ধারণাটি কোনও মডেলটিতে পুনরাবৃত্ত বৈশিষ্ট্যগুলি যুক্ত করা এবং দৃশ্যে সহজেই এটি সংযুক্ত করা অবিশ্বাস্যটিকে সহজ করে তোলা। সমস্ত কয়েক লাইনে।


তাহলে এই আমাকে কি দেয়? সূচকযুক্ত, সম্পাদনা-সক্ষম, পুনরাবৃত্ত বৈশিষ্ট্য।

eventsদোকানে একদিনে উদাহরণস্বরূপ, এবং ক্যালেন্ডার দৃশ্য ব্যবহার করা হয় / সাহায্যকারী বলে task.scheduleদোকানে yaml'd IceCubeবস্তু, তাই আপনার মত কল করতে পারেন: task.schedule.next_suggestion

পুনরুদ্ধার: আমি দুটি মডেল ব্যবহার করি, একটি ফ্ল্যাট, ক্যালেন্ডার প্রদর্শনের জন্য এবং একটি বৈশিষ্ট্যটি কার্যকারিতার জন্য।


আপনি কী নিয়ে এসেছেন তা জানতে আগ্রহী হব। আপনার কাছে কোথাও গিট / ব্লগ / ধারণার প্রমাণ আছে? ধন্যবাদ!
montrealmike

আমি একই রকম কিছু নিয়ে কাজ করছি। আপনার বাস্তবায়নটি দেখতে পছন্দ করবে
25:25

6

পুনরাবৃত্তির পরামিতিগুলি সংরক্ষণ করার জন্য আমি নীচে বর্ণিত ডাটাবেস স্কিমা ব্যবহার করছি

http://github.com/bakineggs/recurring_events_for

তারপরে আমি রুটগুলি গতিশীলভাবে তারিখগুলি গণনা করতে ব্যবহার করি।

https://github.com/mlipper/runt


5
  1. একটি পুনরাবৃত্তির নিয়ম অনুসরণ করুন (সম্ভবত @ ক্রিস কে । প্রতি আইক্যালেন্ডার ভিত্তিতে )। এটিতে একটি প্যাটার্ন এবং একটি ব্যাপ্তি অন্তর্ভুক্ত থাকবে (প্রতি তৃতীয় মঙ্গলবার, 10 টি ইভেন্টের জন্য)।
  2. আপনি যখন কোনও নির্দিষ্ট ঘটনা সম্পাদনা / মুছতে চান, উপরের পুনরাবৃত্তির নিয়মের জন্য ব্যতিক্রমের তারিখগুলি ট্র্যাক রাখুন ( নিয়ম নির্দিষ্ট করে দেওয়ার পরে ইভেন্টটি ঘটে না এমন তারিখ )।
  3. যদি আপনি মুছে ফেলে থাকেন তবে এটাই আপনার প্রয়োজন, আপনি সম্পাদনা করা হলে, অন্য একটি ইভেন্ট তৈরি করুন এবং মূল ইভেন্টে সেট করা প্যারেন্ট আইডি দিন। এই রেকর্ডটিতে মূল ইভেন্টের সমস্ত তথ্য অন্তর্ভুক্ত করা উচিত কিনা আপনি চয়ন করতে পারেন, বা যদি এটি কেবল পরিবর্তনগুলি ধারণ করে এবং পরিবর্তন না করে এমন সমস্ত কিছুর উত্তরাধিকারী হয়।

মনে রাখবেন যে আপনি যদি পুনরাবৃত্তি বিধিগুলি শেষ না করেন তবে আপনি কীভাবে আপনার এখন অসীম তথ্য প্রদর্শন করবেন সে সম্পর্কে আপনাকে ভাবতে হবে।

আশা করি এইটি কাজ করবে!


4

আমি তারিখ লাইব্রেরির শক্তি এবং রুবির পরিসীমা মডিউলটির শব্দার্থক ব্যবহার করার পরামর্শ দেব। একটি পুনরাবৃত্ত ইভেন্ট সত্যিই একটি সময়, একটি তারিখের পরিসীমা (শুরু এবং শেষ) এবং সাধারণত সপ্তাহের একক দিন। তারিখ এবং ব্যাপ্তি ব্যবহার করে আপনি যে কোনও প্রশ্নের উত্তর দিতে পারেন:

#!/usr/bin/ruby
require 'date'

start_date = Date.parse('2008-01-01')
end_date   = Date.parse('2008-04-01')
wday = 5 # friday

(start_date..end_date).select{|d| d.wday == wday}.map{|d| d.to_s}.inspect

লিপ ইয়ার সহ ইভেন্টের সমস্ত দিনই উত্পাদন করে !

# =>"[\"2008-01-04\", \"2008-01-11\", \"2008-01-18\", \"2008-01-25\", \"2008-02-01\", \"2008-02-08\", \"2008-02-15\", \"2008-02-22\", \"2008-02-29\", \"2008-03-07\", \"2008-03-14\", \"2008-03-21\", \"2008-03-28\"]"

2
এটি খুব নমনীয় নয়। একটি পুনরাবৃত্ত ইভেন্টের মডেলটির প্রায়শই পুনরাবৃত্তির সময় নির্দিষ্টকরণ (ঘণ্টা, সাপ্তাহিক, পাক্ষিক, ইত্যাদি) প্রয়োজন হয়। অতিরিক্তভাবে পুনরাবৃত্তিটি মোট সংখ্যার দ্বারা যোগ্যতা অর্জন করতে পারে না, বরং শেষ ঘটনার জন্য একটি শেষ তারিখ
বো জিনেস

"একটি পুনরাবৃত্ত ইভেন্ট হ'ল [..] সাধারণত সপ্তাহের একক দিন", এটি কেবলমাত্র একটি সীমিত ব্যবহারের ক্ষেত্রে এবং এটি 'প্রতি মাসের 5 তম দিন' ইত্যাদির মতো অনেকগুলি পরিচালনা করে না
etc. ই

3

এই উত্তরগুলি থেকে, আমি একটি সমাধান বেরিয়েছি। আমি লিঙ্ক ধারণার ধারণাটি সত্যিই পছন্দ করি। পুনরাবৃত্ত ইভেন্টগুলি একটি সংযুক্ত তালিকা হতে পারে, এর পুনরাবৃত্তির নিয়মটি জানতে লেজযুক্ত। একটি ইভেন্ট পরিবর্তন করা তখন সহজ হবে, কারণ লিঙ্কগুলি স্থির থাকে এবং একটি ইভেন্ট মোছা পাশাপাশি করা সহজ - আপনি কেবল একটি ইভেন্টটিকে লিঙ্কমুক্ত করুন, এটি মুছুন, এবং ইভেন্টটি এর আগে ও পরে পুনরায় লিঙ্ক করুন। আপনাকে এখনও পুনরাবৃত্ত ইভেন্টগুলি জিজ্ঞাসা করতে হবে যখনই কেউ নতুন সময়সীমার দিকে তাকান ক্যালেন্ডারে কখনও তার আগে দেখা হয়নি, তবে অন্যথায় এটি বেশ পরিষ্কার clean


2

আপনি ইভেন্টগুলি পুনরাবৃত্তি হিসাবে সংরক্ষণ করতে পারেন এবং যদি কোনও নির্দিষ্ট উদাহরণ সম্পাদিত হয় তবে একই ইভেন্ট আইডি সহ একটি নতুন ইভেন্ট তৈরি করুন। তারপরে ইভেন্টটি সন্ধান করার সময়, সমস্ত তথ্য পেতে একই ইভেন্ট আইডি সহ সমস্ত ইভেন্ট অনুসন্ধান করুন। আপনি নিজের ইভেন্ট লাইব্রেরিটি ঘূর্ণিত করেছেন কিনা তা আপনি নিশ্চিত নন বা আপনি যদি কোনও বিদ্যমান ব্যবহার করছেন তবে এটি সম্ভব নাও হতে পারে।


আমি এই সমাধানটি একবার ব্যবহার করেছি। আমি পরিবর্তিত উদাহরণটিকে নতুন এক-অফ ইভেন্ট হিসাবে সংরক্ষণ করার নীতিটি পছন্দ করি যা এর মামা কে জানে। এইভাবে আপনি শিশু ইভেন্টের জন্য আলাদা আলাদা ক্ষেত্রগুলি বাদে সমস্ত ক্ষেত্র খালি রাখতে পারবেন can মনে রাখবেন যে আপনার এই মাটির কোন সন্তানটি আপনি সম্পাদনা করছেন তা উল্লেখ করে আপনার একটি অতিরিক্ত ক্ষেত্র থাকতে হবে।
উইটজে

2

তিনটি ভাল রুবি তারিখ / সময় লাইব্রেরির জন্য নীচের নিবন্ধটি দেখুন। বিশেষত আইস_কিউব পুনরাবৃত্তির নিয়ম এবং ইভেন্টের ক্যালেন্ডারের জন্য প্রয়োজন এমন অন্যান্য স্টাফের জন্য দৃ choice় পছন্দ বলে মনে হচ্ছে। http://www.rubyinside.com/3-new-date-and-time-libraries-for-rubyists-3238.html


1

জাভাস্ক্রিপ্টে:

পুনরাবৃত্ত শিডিউল হ্যান্ডলিং: http://bunkat.github.io/later/

এই তফসিলগুলির মধ্যে জটিল ইভেন্টগুলি এবং নির্ভরতাগুলি পরিচালনা করা: http://bunkat.github.io/schedule/

মূলত, আপনি নিয়মগুলি তৈরি করেন তারপরে আপনি lib কে পরবর্তী এন পুনরাবৃত্ত ইভেন্টগুলি গণনা করতে বলেন (একটি তারিখের সীমা নির্দিষ্ট করে বা না)। আপনার মডেল এ সেভ করার জন্য নিয়মগুলি পার্স / ক্রমিক করা যেতে পারে।

আপনার যদি একটি পুনরাবৃত্ত ইভেন্ট থাকে এবং কেবলমাত্র একটি পুনরাবৃত্তি সংশোধন করতে চান তবে আপনি নির্দিষ্ট দিনটিকে বরখাস্ত করতে () বাদে ফাংশনটি ব্যবহার করতে পারেন এবং তারপরে এই প্রবেশের জন্য একটি নতুন পরিবর্তিত ইভেন্ট যুক্ত করতে পারেন।

Lib খুব জটিল নিদর্শন, সময় অঞ্চল এবং এমনকি ক্রোনিং ইভেন্টগুলিকে সমর্থন করে।


0

ইভেন্টগুলি পুনরাবৃত্তি হিসাবে সংরক্ষণ করুন এবং এগুলি গতিশীলভাবে প্রদর্শন করুন, তবে পুনরাবৃত্ত ইভেন্টগুলিকে নির্দিষ্ট ইভেন্টগুলির একটি তালিকা থাকতে দেয় যা কোনও নির্দিষ্ট দিনে ডিফল্ট তথ্যকে ওভাররাইড করতে পারে।

যখন আপনি পুনরাবৃত্ত ইভেন্টের প্রশ্ন করেন তখন সেদিনের জন্য একটি নির্দিষ্ট ওভাররাইড পরীক্ষা করতে পারে।

যদি কোনও ব্যবহারকারী পরিবর্তন করে থাকে তবে আপনি জিজ্ঞাসা করতে পারেন যে তিনি সমস্ত দৃষ্টান্তের জন্য (ডিফল্ট বিবরণ) আপডেট করতে চান বা ঠিক সেদিন (একটি নতুন নির্দিষ্ট ইভেন্ট তৈরি করুন এবং এটি তালিকায় যুক্ত করুন)।

যদি কোনও ব্যবহারকারী এই ইভেন্টের সমস্ত পুনরাবৃত্তি মুছে ফেলতে বলে তবে আপনার কাছেও নির্দিষ্টকরণের তালিকা রয়েছে এবং সেগুলি সহজেই মুছে ফেলতে পারেন।

একমাত্র সমস্যাযুক্ত কেসটি হ'ল যদি ব্যবহারকারী এই ইভেন্টটি এবং ভবিষ্যতের সমস্ত ইভেন্ট আপডেট করতে চান। কোন ক্ষেত্রে আপনাকে পুনরাবৃত্ত ইভেন্ট দুটি ভাগে ভাগ করতে হবে। এই মুহুর্তে আপনি কোনওভাবে পুনরাবৃত্ত ইভেন্টগুলিকে লিঙ্ক করা বিবেচনা করতে পারেন যাতে আপনি সেগুলি সমস্ত মুছতে পারেন।


0

.NET প্রোগ্রামারদের জন্য যারা কিছু লাইসেন্স ফি প্রদানের জন্য প্রস্তুত, আপনি Aspose.Network দরকারী খুঁজে পেতে পারেন ... এটি পুনরাবৃত্ত অ্যাপয়েন্টমেন্টের জন্য একটি আইক্যালেন্ডার সামঞ্জস্যপূর্ণ লাইব্রেরি অন্তর্ভুক্ত।


0

আপনি ইভেন্টগুলিকে সরাসরি আইক্যালেন্ডার ফর্ম্যাটে সঞ্চয় করেন, যা ওপেন-এন্ডেড পুনরাবৃত্তি, সময়-অঞ্চল স্থানীয়করণ এবং এর জন্য আরও অনুমতি দেয়।

এগুলি আপনি কোনও ক্যালডিএভি সার্ভারে সঞ্চয় করতে পারেন এবং তারপরে আপনি যখন ইভেন্টগুলি প্রদর্শন করতে চান তখন আপনি ক্যালডিএভি-তে সংজ্ঞায়িত প্রতিবেদনের বিকল্পটি সার্ভারকে দেখা সময়ের মধ্যে পুনরাবৃত্ত ইভেন্টগুলির প্রসারণ করতে জিজ্ঞাসা করতে পারেন।

অথবা আপনি এগুলি নিজেই একটি ডাটাবেসে সংরক্ষণ করতে পারেন এবং প্রসারিত করতে কোনও ধরণের আইক্যালেন্ডার পার্সিং লাইব্রেরি ব্যবহার করতে পারেন, ব্যাকএন্ড ক্যালডাভি সার্ভারের সাথে কথা বলার জন্য পিটি / জিইটি / রিপোর্টের প্রয়োজন ছাড়াই। এটি সম্ভবত আরও কাজ - আমি নিশ্চিত ক্যালডিএভি সার্ভারগুলি কোথাও জটিলতা লুকায়।

আইক্যালেন্ডার ফর্ম্যাটে ইভেন্টগুলি সম্ভবত দীর্ঘমেয়াদে জিনিসগুলিকে আরও সহজ করে তুলবে কারণ লোকেরা সর্বদা তাদের অন্য সফ্টওয়্যারে রাখার জন্য রফতানি করতে চাইবে।


0

আমি এই বৈশিষ্ট্যটি সহজভাবে প্রয়োগ করেছি! লজিকটি নিম্নরূপ, প্রথমে আপনার দুটি টেবিলের প্রয়োজন। RuleTable স্টোর সাধারণ বা পিতৃতান্ত্রিক ঘটনা পুনর্ব্যবহার। আইটেম টেবিলটি চক্রের ইভেন্টগুলি সঞ্চিত। উদাহরণস্বরূপ, যখন আপনি একটি চক্রীয় ইভেন্ট তৈরি করেন, 6 নভেম্বর 2015 এর শুরু করার সময়, 6 ডিসেম্বরের শেষ সময় (বা চিরকাল), এক সপ্তাহের জন্য চক্র। আপনি একটি রুল টেবিলের মধ্যে ডেটা sertোকান, ক্ষেত্রগুলি নিম্নরূপ:

TableID: 1 Name: cycleA  
StartTime: 6 November 2014 (I kept thenumber of milliseconds),  
EndTime: 6 November 2015 (if it is repeated forever, and you can keep the value -1) 
Cycletype: WeekLy.

এখন আপনি 20 নভেম্বর থেকে 20 ডিসেম্বর তথ্য জিজ্ঞাসা করতে চান। আপনি রিক্রুরিং এভেন্টবি (একটি দীর্ঘ সূচনা, দীর্ঘ প্রান্ত) একটি ফাংশন লিখতে পারেন, আরম্ভের ও সমাপ্ত সময়ের উপর ভিত্তি করে উইকএল, আপনি যে সংগ্রহটি চান তা গণনা করতে পারেন, <ਚੱਕਰA11.20, চক্র 11.27, চক্র 12.4 ......>। 6 নভেম্বর ছাড়াও, এবং বাকি আমি তাকে একটি ভার্চুয়াল ইভেন্ট বলেছি। যখন ব্যবহারকারী কোনও ভার্চুয়াল ইভেন্টের নাম পরিবর্তন করে (উদাহরণস্বরূপ سائیکلএ 11.27), আপনি একটি আইটেম টেবিলের মধ্যে একটি ডেটা inোকান। ক্ষেত্রগুলি নিম্নরূপ:

TableID: 1 
Name, cycleB  
StartTime, 27 November 2014  
EndTime,November 6 2015  
Cycletype, WeekLy
Foreignkey, 1 (pointingto the table recycle paternal events).

RecurringEventBE ফাংশনে (দীর্ঘ শুরু, দীর্ঘ শেষ), আপনি আমার ইংরেজি সম্পর্কে দুঃখিত ভার্চুয়াল ইভেন্ট (চক্রবি 11.27) কভার করে এই ডেটা ব্যবহার করেন, আমি চেষ্টা করেছি।

এটি আমার পুনরাবৃত্তি ইভেন্ট E

public static List<Map<String, Object>> recurringData(Context context,
        long start, long end) { // 重复事件的模板处理,生成虚拟事件(根据日期段)
     long a = System.currentTimeMillis();
    List<Map<String, Object>> finalDataList = new ArrayList<Map<String, Object>>();

    List<Map<String, Object>> tDataList = BillsDao.selectTemplateBillRuleByBE(context); //RuleTablejust select recurringEvent
    for (Map<String, Object> iMap : tDataList) {

        int _id = (Integer) iMap.get("_id");
        long bk_billDuedate = (Long) iMap.get("ep_billDueDate"); // 相当于事件的开始日期 Start
        long bk_billEndDate = (Long) iMap.get("ep_billEndDate"); // 重复事件的截止日期 End
        int bk_billRepeatType = (Integer) iMap.get("ep_recurringType"); // recurring Type 

        long startDate = 0; // 进一步精确判断日记起止点,保证了该段时间断获取的数据不未空,减少不必要的处理
        long endDate = 0;

        if (bk_billEndDate == -1) { // 永远重复事件的处理

            if (end >= bk_billDuedate) {
                endDate = end;
                startDate = (bk_billDuedate <= start) ? start : bk_billDuedate; // 进一步判断日记起止点,这样就保证了该段时间断获取的数据不未空
            }

        } else {

            if (start <= bk_billEndDate && end >= bk_billDuedate) { // 首先判断起止时间是否落在重复区间,表示该段时间有重复事件
                endDate = (bk_billEndDate >= end) ? end : bk_billEndDate;
                startDate = (bk_billDuedate <= start) ? start : bk_billDuedate; // 进一步判断日记起止点,这样就保证了该段时间断获取的数据不未空
            }
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(bk_billDuedate); // 设置重复的开始日期

        long virtualLong = bk_billDuedate; // 虚拟时间,后面根据规则累加计算
        List<Map<String, Object>> virtualDataList = new ArrayList<Map<String, Object>>();// 虚拟事件

        if (virtualLong == startDate) { // 所要求的时间,小于等于父本时间,说明这个是父事件数据,即第一条父本数据

            Map<String, Object> bMap = new HashMap<String, Object>();
            bMap.putAll(iMap);
            bMap.put("indexflag", 1); // 1表示父本事件
            virtualDataList.add(bMap);
        }

        long before_times = 0; // 计算从要求时间start到重复开始时间的次数,用于定位第一次发生在请求时间段落的时间点
        long remainder = -1;
        if (bk_billRepeatType == 1) {

            before_times = (startDate - bk_billDuedate) / (7 * DAYMILLIS);
            remainder = (startDate - bk_billDuedate) % (7 * DAYMILLIS);

        } else if (bk_billRepeatType == 2) {

            before_times = (startDate - bk_billDuedate) / (14 * DAYMILLIS);
            remainder = (startDate - bk_billDuedate) % (14 * DAYMILLIS);

        } else if (bk_billRepeatType == 3) {

            before_times = (startDate - bk_billDuedate) / (28 * DAYMILLIS);
            remainder = (startDate - bk_billDuedate) % (28 * DAYMILLIS);

        } else if (bk_billRepeatType == 4) {

            before_times = (startDate - bk_billDuedate) / (15 * DAYMILLIS);
            remainder = (startDate - bk_billDuedate) % (15 * DAYMILLIS);

        } else if (bk_billRepeatType == 5) {

            do { // 该段代码根据日历处理每天重复事件,当事件比较多的时候效率比较低

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH, 1);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 1 + 1);
                    virtualLong = calendar.getTimeInMillis();
                } else {
                    calendar.add(Calendar.MONTH, 1);
                    virtualLong = calendar.getTimeInMillis();
                }

            } while (virtualLong < startDate);

        } else if (bk_billRepeatType == 6) {

            do { // 该段代码根据日历处理每天重复事件,当事件比较多的时候效率比较低

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH, 2);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 2 + 2);
                    virtualLong = calendar.getTimeInMillis();
                } else {
                    calendar.add(Calendar.MONTH, 2);
                    virtualLong = calendar.getTimeInMillis();
                }

            } while (virtualLong < startDate);

        } else if (bk_billRepeatType == 7) {

            do { // 该段代码根据日历处理每天重复事件,当事件比较多的时候效率比较低

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH, 3);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 3 + 3);
                    virtualLong = calendar.getTimeInMillis();
                } else {
                    calendar.add(Calendar.MONTH, 3);
                    virtualLong = calendar.getTimeInMillis();
                }

            } while (virtualLong < startDate);

        } else if (bk_billRepeatType == 8) {

            do {
                calendar.add(Calendar.YEAR, 1);
                virtualLong = calendar.getTimeInMillis();
            } while (virtualLong < startDate);

        }

        if (remainder == 0 && virtualLong != startDate) { // 当整除的时候,说明当月的第一天也是虚拟事件,判断排除为父本,然后添加。不处理,一个月第一天事件会丢失
            before_times = before_times - 1;
        }

        if (bk_billRepeatType == 1) { // 单独处理天事件,计算出第一次出现在时间段的事件时间

            virtualLong = bk_billDuedate + (before_times + 1) * 7
                    * (DAYMILLIS);
            calendar.setTimeInMillis(virtualLong);

        } else if (bk_billRepeatType == 2) {

            virtualLong = bk_billDuedate + (before_times + 1) * (2 * 7)
                    * DAYMILLIS;
            calendar.setTimeInMillis(virtualLong);
        } else if (bk_billRepeatType == 3) {

            virtualLong = bk_billDuedate + (before_times + 1) * (4 * 7)
                    * DAYMILLIS;
            calendar.setTimeInMillis(virtualLong);
        } else if (bk_billRepeatType == 4) {

            virtualLong = bk_billDuedate + (before_times + 1) * (15)
                    * DAYMILLIS;
            calendar.setTimeInMillis(virtualLong);
        }

        while (startDate <= virtualLong && virtualLong <= endDate) { // 插入虚拟事件
            Map<String, Object> bMap = new HashMap<String, Object>();
            bMap.putAll(iMap);
            bMap.put("ep_billDueDate", virtualLong);
            bMap.put("indexflag", 2); // 2表示虚拟事件
            virtualDataList.add(bMap);

            if (bk_billRepeatType == 1) {

                calendar.add(Calendar.DAY_OF_MONTH, 7);

            } else if (bk_billRepeatType == 2) {

                calendar.add(Calendar.DAY_OF_MONTH, 2 * 7);

            } else if (bk_billRepeatType == 3) {

                calendar.add(Calendar.DAY_OF_MONTH, 4 * 7);

            } else if (bk_billRepeatType == 4) {

                calendar.add(Calendar.DAY_OF_MONTH, 15);

            } else if (bk_billRepeatType == 5) {

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH,
                        1);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 1
                            + 1);
                } else {
                    calendar.add(Calendar.MONTH, 1);
                }

            }else if (bk_billRepeatType == 6) {

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH,
                        2);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 2
                            + 2);
                } else {
                    calendar.add(Calendar.MONTH, 2);
                }

            }else if (bk_billRepeatType == 7) {

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH,
                        3);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 3
                            + 3);
                } else {
                    calendar.add(Calendar.MONTH, 3);
                }

            } else if (bk_billRepeatType == 8) {

                calendar.add(Calendar.YEAR, 1);

            }
            virtualLong = calendar.getTimeInMillis();

        }

        finalDataList.addAll(virtualDataList);

    }// 遍历模板结束,产生结果为一个父本加若干虚事件的list

    /*
     * 开始处理重复特例事件特例事件,并且来时合并
     */
    List<Map<String, Object>>oDataList = BillsDao.selectBillItemByBE(context, start, end);
    Log.v("mtest", "特例结果大小" +oDataList );


    List<Map<String, Object>> delectDataListf = new ArrayList<Map<String, Object>>(); // finalDataList要删除的结果
    List<Map<String, Object>> delectDataListO = new ArrayList<Map<String, Object>>(); // oDataList要删除的结果


    for (Map<String, Object> fMap : finalDataList) { // 遍历虚拟事件

        int pbill_id = (Integer) fMap.get("_id");
        long pdue_date = (Long) fMap.get("ep_billDueDate");

        for (Map<String, Object> oMap : oDataList) {

            int cbill_id = (Integer) oMap.get("billItemHasBillRule");
            long cdue_date = (Long) oMap.get("ep_billDueDate");
            int bk_billsDelete = (Integer) oMap.get("ep_billisDelete");

            if (cbill_id == pbill_id) {

                if (bk_billsDelete == 2) {// 改变了duedate的特殊事件
                    long old_due = (Long) oMap.get("ep_billItemDueDateNew");

                    if (old_due == pdue_date) {

                        delectDataListf.add(fMap);//该改变事件在时间范围内,保留oMap

                    }

                } else if (bk_billsDelete == 1) {

                    if (cdue_date == pdue_date) {

                        delectDataListf.add(fMap);
                        delectDataListO.add(oMap);

                    }

                } else {

                    if (cdue_date == pdue_date) {
                        delectDataListf.add(fMap);
                    }

                }

            }
        }// 遍历特例事件结束

    }// 遍历虚拟事件结束
    // Log.v("mtest", "delectDataListf的大小"+delectDataListf.size());
    // Log.v("mtest", "delectDataListO的大小"+delectDataListO.size());
    finalDataList.removeAll(delectDataListf);
    oDataList.removeAll(delectDataListO);
    finalDataList.addAll(oDataList);
    List<Map<String, Object>> mOrdinaryList = BillsDao.selectOrdinaryBillRuleByBE(context, start, end);
    finalDataList.addAll(mOrdinaryList);
    // Log.v("mtest", "finalDataList的大小"+finalDataList.size());
    long b = System.currentTimeMillis();
    Log.v("mtest", "算法耗时"+(b-a));

    return finalDataList;
}   

-5

আপনার যদি শেষের তারিখ না দিয়ে পুনরাবৃত্ত অ্যাপয়েন্টমেন্ট হয়? স্থান যতটা সস্তা, আপনার কাছে অসীম স্থান নেই, সুতরাং সলিউশন 2 হ'ল সেখানে অ-স্টার্টার ...

আমি পরামর্শ দিতে পারি যে "শেষের তারিখটি" শতাব্দীর শেষে কোনও শেষের তারিখে সমাধান করা যাবে। এমনকি একটি প্রতিদিনের ইভেন্টের জন্য জায়গার পরিমাণ সস্তা থাকে।


7
কত শীঘ্রই আমরা y2k এর পাঠগুলি ভুলে যাচ্ছি ... :)
ইয়ান মেরার

10
আসুন ধরে নেওয়া যাক আমাদের প্রতিদিনের বেশ কয়েকটি ইভেন্টের সাথে 1000 জন ব্যবহারকারী রয়েছেন। 3 টি ইভেন্ট × 1000 ব্যবহারকারী × 365 দিন × (2100-2011 = 89 বছর) = 97.5 মিলিয়ন রেকর্ড। পরিবর্তে 3000 "পরিকল্পনা"। উম ...
অ্যান্ডি মিখাইলেনকো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.